5.2.1面向可维护性的设计模式(工厂方法和抽象工厂)

关于如何“创建类的新实例”的模式

(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. 不必在每次调用的时候都创建新对象
  3. 可以返回原返回类型的任意子类型

工厂方法的好处

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抽象工厂可调用多个工厂。
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值