关于如何“创建类的新实例”的模式
(1)工厂方法模式
什么时候使用工厂方法
(1)当client不知道/不确定要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
(2)定义一个用于创建对象的接口,让该接口的子类型来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
工厂方法实例
这是抽象方法
。
public interface Trace {
// turn on and off debugging
public void setDebug( boolean debug );
// write out a debug message
public void debug( String message );
// write out an error message
public void error( String message );
}
这是具体方法1(注意具体方法1,具体方法2与抽象方法的比较)
。
public class FileTrace implements Trace {
private PrintWriter pw;
private boolean debug;
public FileTrace() throws IOException {
pw = new PrintWriter( new FileWriter( "t.log" ) );
}
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) {
pw.println( "DEBUG: " + message );
pw.flush();
}
}
public void error( String message ) {
pw.println( "ERROR: " + message );
pw.flush();
}
}
这是具体方法2(注意具体方法1,具体方法2与抽象方法的比较)
。
public class SystemTrace implements Trace {
private boolean debug;
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug )
System.out.println( "DEBUG: " + message );
}
public void error( String message ) {
System.out.println( "ERROR: " + message );
}
}
如何使用具体方法1
和具体方法2
//... some code ...
Trace log1 = new SystemTrace();
log1.debug("entering log");
Trace log2 = new FileTrace();
log2.debug("... ");
抽象方法
自身还可以加强
//不仅包含factory method,还可以实现其他功能
interface TraceFactory {
Trace getTrace();
void otherOperation();
}
getTrace()的具体实现下放到具体类
//有新的具体产品类加入时,可以增加新的工厂类或修改已有工厂类,不会影响客户端代码(OCP)
public class SystemTraceFactory implements TraceFactory {
public Trace getTrace() {
… //other operations
return new SystemTrace();
}
}
public class FileTraceFactory implements TraceFactory {
public Trace getTrace() {
return new FileTrace();
}
}
Client使用“工厂方法”
来创建实例,得到实例的类型是抽象接口而非具体类。
//... some code ...
Trace log1 = new SystemTraceFactory().getTrace();
log1.debug("entering log");
Trace log2 = new FileTraceFactory().getTrace();
log2.debug("...");
抽象方法
还可以再加强
interface TraceFactory {
Trace getTrace(String type);
void otherOperation();
}
另外一种实现方式:也可以根据类型决定创建哪个具体产品
public class Factory implements TraceFactory {
public getTrace(String type) {
if(type.equals("file" )
return new FileTrace();
else if (type.equals("system")
return new SystemTrace();
}
}
客户端
Trace log = new Factory().getTrace("system");
log.setDebug(false);
log.debug("...");
静态工厂方法
:既可以在ADT内部实现,也可以构造单独的工厂类
public class SystemTraceFactory{
public static Trace getTrace() {
return new SystemTrace();
}
}
public class TraceFactory {
public static Trace getTrace(String type) {
if(type.equals("file")
return new FileTrace();
else if (type.equals("system")
return new SystemTrace();
}
}
客户端
//... some code ...
Trace log1 = SystemTraceFactory.getTrace();
log1.setDebug(true);
log1.debug( "entering log" );
Trace log2 = TraceFactory.getTrace("system");
log1.setDebug(true);
log2.debug("... ");
相比于通过构造器(new)构建对象:
- 静态工厂方法可具有指定的名称
- 不必在每次调用的时候都创建新对象
- 可以返回原返回类型的任意子类型
工厂方法的好处
1.消除了将特定于应用程序的类绑定到代码的需要。
2. 代码只处理Product interface(Trace),因此它可以处理任何用户定义的ConcreteProduct(FileTrace、SystemTrace)
工厂方法的坏处
1.每增加一种产品就需要增加一个新的工 厂子类
2.如果客户只创建Creator的副类,工厂方法就是可以接受的,否则,客户必须对Creator进行更新
拙见
总的来说,工厂方法定义了一个包含很多泛用的方法的接口,而子类对工厂方法的不同的实现可以使得工厂方法的功能多元化,并且还可以根据类型选择新产品,同时创建,调用子类也极其方便。
(2)抽象工厂模式
适用于抽象工厂模式的几种场景
1.一个UI,包含多个窗口控件,这些控件的组合在不同的OS中实现不同。
2.一个智能房屋的设备管理系统,要控制多个设备,这些设备的制造商各有不同,控制接口有差异
抽象工厂模式:提供接口以创建一组相关/相互依赖的对象,
但不需要指明其具体实现类。
抽象工厂实例
Abstract Factory创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的object,各产品创建过程对client可见,但“搭配”不能改变。本质上,Abstract Factory是把多类产品的factory method组合在一起
抽象工厂举例
1.一个恒星系由一个恒星和一组行星组成
2.一个用户软件系统由一个用户和一组软件应用组成
3.L和PhysicalObject的类型,要有固定搭配,不能随意组合
抽象工厂VS工厂方法
1.工厂方法创建一个对象VS抽象工厂创建多个类型的对象。
2.工厂方法为一个工厂VS抽象工厂可调用多个工厂。