简单工厂模式:
当代吗使用具体类时,一旦加入新的具体类,就必须要改变代码(import该类)。我们希望在生成对象的时候,不使用new+具体类的名称,而是希望调用一个简单的方法,传递一个参数过去,就可以返回一个具体的对象。通过这种方法,我们减少了我们对其他代码的类的名称的依赖。
简单例子的类图如下
如图所示,相比于原来,如果要提供四种pizza对象,用户需要知道内部四个类的名称进行创建,如果类的名称修改,客户的程序将无法运行正常。而采取简单工厂模式的耦合只有一个方法。
工厂方法模式:
又称之为虚拟构造器,父类负责定义创建类的公共接口,子类负责生成具体对象。
以上述例子为例,制作pizza对象只有simplypizzafactory负责。但是如果要实现制作pizza对象的的不同流程,就需要新增工厂。
假设用户在上面的例子中需要新加对象的产生流程,在不修改源代码的情况下,可以在原来的代码中添加新的工厂。这便是工厂方法模式。
注意,用户如果想要生成pizza对象,需要先生成工厂对象,再按照工厂对象所遵循的抽象接口生成pizza对象。所以耦合度为工厂的类的名称和工厂所遵循的抽象接口。
抽象工厂模式
如果在工厂模式下,需要添加一种新的抽象产品,比如说除了pizza还要售卖Hotdog,工厂方法仍然避免如果完全新增一种抽象产品的修改。所以采用抽象工厂法
继承于同一个抽象产品的被称之为产品等级结构,由同一个抽象工厂生产的产品被称之为产品族。如果每个产品族只有一个产品,则退回到工厂方法
应用
- 防范在构造对象过程中this引用从本线程中逸出。
不要在构造函数中将被对象的this的引用显示或者隐式的泄露出去(就是保证在构造完成保证this对象不被非构造线程可见)
public class ThisEscape {
public final int id;
public final String name;
public ThisEscape(EventSource<EventListener> source) {//此时,外部线程就可以通过其持有的souce引用访问这个对象了。而此时,对象的构造还没有完成
id = 1;
source.registerListener(new EventListener() {
public void onEvent(Object obj) {
System.out.println("id: "+ThisEscape.this.id);
System.out.println("name: "+ThisEscape.this.name);
}
});
name = "flysqrlboy";
}
}
上述代码应该更改为工厂方法
public class ThisSafe {
public final int id;
public final String name;
private final EventListener listener;
private ThisSafe() {
id = 1;
listener = new EventListener(){
public void onEvent(Object obj) {
System.out.println("id: "+ThisSafe.this.id);
System.out.println("name: "+ThisSafe.this.name);
}
};
name = "flysqrlboy";
}
//采取工厂方法
public static ThisSafe getInstance(EventSource<EventListener> source) {
ThisSafe safe = new ThisSafe();
source.registerListener(safe.listener);
return safe;
}
}
另外,基于同样的原因,我们不能在构造函数中启动线程,所以,我们需要工厂方法来启动线程。