注意:简单工厂模式 违背了六大原则中的开发-封闭原则,故而不属于23种GOF设计模式之一 也叫静态工厂方法模式
单例模式的实现需要三个必要的条件:
另外,实现单例类时,还需要考虑三个问题:
下面介绍五种实现单例模式的方式。
饿汉式的单例实现比较简单,其在类加载的时候,静态实例 instance 就已创建并初始化好了。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton () {}
public static Singleton getInstance() {
return instance;
}
}
饿汉式单例优缺点:
一般认为延时加载可以节省内存资源。但是延时加载是不是真正的好,要看实际的应用场景,而不一定所有的应用场景都需要延时加载。
与饿汉式对应的是懒汉式,懒汉式为了支持延时加载,将对象的创建延迟到了获取对象的时候,但为了线程安全,不得不为获取对象的操作加锁,这就导致了低性能。
public class Singleton {
private static final Singleton instance;
private Singleton () {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式单例优缺点:
饿汉式和懒汉式的单例都有缺点,双重检测的实现方式解决了这两者的缺点。
双重检测将懒汉式中的 synchronized 方法改成了 synchronized 代码块。
public class Singleton {
private static Singleton instance;
private Singleton () {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) { // 注意这里是类级别的锁
if (instance == null) { // 这里的检测避免多线程并发时多次创建对象
instance = new Singleton();
}
}
}
return instance;
}
}
双重检测单例优点:
包括简单工厂模式、抽象工厂模式、工厂方法模式
public class SimpleFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ProductA();
} else if (type.equals("B")) {
return new ProductB();
} else {
return null;
}
}
}
public interface Product {
void use();
}
public class ProductA implements Product {
@Override
public void use() {
System.out.println("Using Product A");
}
}
public class ProductB implements Product {
@Override
public void use() {
System.out.println("Using Product B");
}
}
b. 工厂方法模式:修正了简单工厂模式中不遵守开放封闭原则。把选择判断移到了客户端去实现,如果想添加新功能就不用修改原来的类,直接修改客户端即可。
public interface Factory {
Product createProduct();
}
public class ProductAFactory implements Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
public class ProductBFactory implements Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
c. 抽象工厂模式:定义了一个创建一系列相关或相互依赖的接口,而无需指定他们的具体类。
public interface AbstractFactory {
Product createProductA();
Product createProductB();
}
---
public class AbstractProductFactory implements AbstractFactory {
@Override
public Product createProductA() {
return new ProductAFactory().createProduct();
}
@Override
public Product createProductB() {
return new ProductBFactory().createProduct();
}
}
public class Client {
public static void main(String[] args) {
AbstractFactory factory = new AbstractProductFactory();
Product productA = factory.createProductA();
Product productB = factory.createProductB();
productA.use();
productB.use();
}
}
定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,主题对象发生变化时,会通知所有的观察者,使他们能够更新自己。(微信朋友圈动态通知、消息通知、邮件通知、广播通知、桌面程序的事件响应)
在观察者模式中,又分为推模型和拉模型两种方式。
主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成派生类更为灵活。(输入输出流)
文件流 -> 输入输出流 -> 缓冲池流 (层层包装,扩展功能)
BufferedReader in1 = new BufferedReader(new InputStreamReader(new FileInputStream(file)));//字符流
DataInputStream in2 = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));//字节流
// DataInputStream-从数据流读取字节,并将它们装换为正确的基本类型值或字符串
// BufferedInputStream-可以通过减少读写次数来提高输入和输出的速度
建造者模式的目的是为了分离对象的属性与创建过程。
建造者模式是构造方法的一种替代方案,为什么需要建造者模式,我们可以想,假设有一个对象里面有20个属性:
● 属性1
● 属性2
● ...
● 属性20
对开发者来说这不是疯了,也就是说我要去使用这个对象,我得去了解每个属性的含义,然后在构造函数或者Setter中一个一个去指定。更加复杂的场景是,这些属性之间是有关联的,比如属性1=A,那么属性2只能等于B/C/D,这样对于开发者来说更是增加了学习成本,开源产品这样的一个对象相信不会有太多开发者去使用。
为了解决以上的痛点,建造者模式应运而生,对象中属性多,但是通常重要的只有几个,因此建造者模式会让开发者指定一些比较重要的属性或者让开发者指定某几个对象类型,然后让建造者去实现复杂的构建对象的过程,这就是对象的属性与创建分离。这样对于开发者而言隐藏了复杂的对象构建细节,降低了学习成本,同时提升了代码的可复用性。
@Data
public class CarBuilder {
// 车型
private String type;
// 动力
private String power;
public Car build() {
Assert.assertNotNull(type);
Assert.assertNotNull(power);
return new Car(this);
}
public CarBuilder type(String type) {
this.type = type;
return this;
}
public CarBuilder power(String power) {
this.power = power;
return this;
}
}
@Test
public void test() {
Car car = new CarBuilder()
.power("动力一般")
.type("紧凑型车")
.build();
System.out.println(JSON.toJSONString(car));
}
Aop 就是使用代理模式来实现的。
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject handles the request");
}
}
---
public class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
System.out.println("Proxy handles the request");
// before aop
realSubject.request();
// post aop
}
}
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}
优缺点
public interface Strategy {
void execute();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("Executing strategy A");
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("Executing strategy B");
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
public class Client {
public static void main(String[] args) {
Strategy strategyA = new ConcreteStrategyA();
Strategy strategyB = new ConcreteStrategyB();
Context context = new Context(strategyA);
context.executeStrategy();
context = new Context(strategyB);
context.executeStrategy();
}
}