工厂方法模式(Factory Method)简介

工厂方法模式 名字 跟已经介绍的 简单工厂模式很类似.

实际上它们的模型也是十分相似的.


我们先看看工厂模式的定义.


一. 工厂方法(Factory Method)模式定义

教材上是这样写的:

工厂方法模式(Factory Method):

定义1个用于创建对象的接口, 让子类决定实例化哪个类.   工厂模式使1个类的实例化延迟到其子类.


是不是觉得定义很恶心, 我也觉得, 刚开始完全看不懂啊.


这里稍稍先分析一下.

定义1个用于创建对象接口, 让子类决定实例化哪个.   工厂模式使1个的实例化延迟到其子类.


上面那句话出现了4个对象.

分别是: 对象 接口 子类


它们的关系是这样的:

是指业务类,

对象  的实例化对象.


接口 指Java 的 interface 或者 抽象类. (工厂)

子类接口 的子类(或者叫实现类).



(工厂)子类 会创建1个 (业务)类对象


至于延迟是什么意思?  还是在下面举个例子来讲把.



二. 手机的例子.

显示上手机有很多种. (包括Nokia手机, BlackBerry手机)

常用的功能有3种.

1. 打电话,

2. 发邮件.

3. 播放mp3.


现在有个人很有钱任性.

他有3台Nokia , 1台在打电话, 一台发邮件, 一台听歌..


用代码如何实现呢.


三. 简单工厂模式实现.

UML:




CellPhone接口:

public interface CellPhone {
	public abstract void call();
	public abstract void playMusic();
	public abstract void sendEmail();
}

BlackBerry:

public class BlackBerry implements CellPhone {
	@Override
	public void call(){
		System.out.println("calling by BlackBerry");
	}

	@Override
	public void playMusic(){
		System.out.println("playing Music by BlackBerry");
	}

	@Override
	public void sendEmail(){
		System.out.println("sending Email by BlackBerry");
	}

}

Nokia:

public class Nokia implements CellPhone {
	@Override
	public void call(){
		System.out.println("calling by nokia");
	}

	@Override
	public void playMusic(){
		System.out.println("playing Music by nokia");
	}

	@Override
	public void sendEmail(){
		System.out.println("sending Email by nokia");
	}

}


工厂类CellPhoneFactory:

public class CellPhoneFactory {
	public static CellPhone createCellPhone(String name){
		CellPhone p = null;
		switch(name){
		case "Nokia" : 
			p = new Nokia(); 
			break;
		case "BlackBerry" : 
			p = new BlackBerry(); 
			break;
		}
		
		return p;
	}
}




客户端:

	String name = "Nokia";
		CellPhone p = CellPhoneFactory.createCellPhone(name);
		CellPhone p2 = CellPhoneFactory.createCellPhone(name);
		CellPhone p3 = CellPhoneFactory.createCellPhone(name);
		
		p.call();
		p2.sendEmail();
		p3.playMusic();



四. 简单工厂的1个缺点.

简单工厂对客户端封装了真正的业务类, 这是以前说过的.

但是如果我要增加1个业务, 例如那个人想用一台Sony手机.


除了修改客户端代码外

那么我必须新增1个Sony类  -> 符合封闭-开放原则

还必须修改工厂类代码, 增加1个case 字句 -> 不符合封闭-开放原则,     原则上是不应该修改原有类的.




五. 工厂方法的实现.

UML:



其中CellPhone, BlackBerry, Nokia3个类或接口跟上面是一样的没有变化.

工厂抽象类CellPhoneFactory:

现在这个类变成了抽象类了.

public abstract class CellPhoneFactory {
	public abstract CellPhone createCellPhone();
}



NokiaFactory:

Nokia工厂, 只会创建Nokia对象,  而且创建对象的方法已经不是静态方法, 需要实例化1个工厂来创建.

public class NokiaFactory extends CellPhoneFactory{
	@Override
	public CellPhone createCellPhone(){
		return new Nokia();
	}
}


BlackBerryFactory:

public class BlackBerryFactory extends CellPhoneFactory{
	@Override
	public CellPhone createCellPhone(){
		return new BlackBerry();
	}
}

客户端代码:

	CellPhoneFactory factory = new NokiaFactory();
		CellPhone p = factory.createCellPhone();
		CellPhone p2 = factory.createCellPhone();
		CellPhone p3 = factory.createCellPhone();
		
		p.call();
		p2.sendEmail();
		p3.playMusic();




六. 工厂方法与简单工厂方法的区别.

好了, 通过对比, 我们知道区别如下:


1. 简单工厂的工厂类是1个非抽象类.  而工厂方法的工厂类是一个抽象类(或者接口), 它下面还有子类.


2. 简单工厂的业务类对象由工厂类的静态方法直接创建, 而工厂方法的业务类对象由工厂类的子类来创建.

这个就是工厂方法里, 那句" 工厂模式使1个的实例化延迟到其子类" 的原因,  延迟是相当于简单工厂来讲的.




如果要新增1个sony手机.

工厂方法, 除了修改客户端代码之外,

还需要

新加个sony手机类.

新家1个sony手机工厂类.


看起来是完全符合开放-封闭原则的.


但是实际上,  简单工厂方法的判断在工厂类的switch字句内.

而工厂方法看起来不需要判断, 但实际上是把判断交给了客户端.


也就是说这一句

CellPhoneFactory factory = new NokiaFactory();

客户端需要自己判断使用哪个工厂.


而简单工厂只需要传入"Nokia"的名字就得到对应的业务对象.


有没有折中方法呢? 就是只需要手机名字的参数,  而且符合开放封闭原则的写法.

那就需要利用java里的反射机制.(所谓反射就是可以根据类名获取哪个类的对象或其他资源)



七. 反射简单工厂.

重写简单工厂的工厂类,   不使用switch 字句, 而是java的反射..

public class CellPhoneReflectFactory {
	public static CellPhone createCellPhone(String name){
		Class<?> c = null;
		Class<?>[] argTypes = {}; //指明所要调用的构造方法的形参  
		Constructor<?> cst = null;
		CellPhone p = null;
		Object obj = null;
		try {
			c = (Class<?>) Class.forName("factory.simple." + name);
			cst = c.getConstructor(argTypes);//获取指定参数的构造方法
			obj = cst.newInstance(argTypes);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		p = (CellPhone)obj;
		return p;
	}
}

而客户端的写发不需要改变, 新增业务类也无需修改这个工厂类了.












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值