首页 > 代码库 > 读秦小波《设计模式之禅》 -- 工厂模式

读秦小波《设计模式之禅》 -- 工厂模式

      设计模式是一种非常有用的编程技巧,它对于代码的重构有些非常重要的作用,对于软件开发人员来说,需要理解并尝试着使用这些设计的方法。

      个人感觉《设计模式之禅》这本书中讲解的非常具体,每个模式都配以适当的例子,非常适合学习设计模式的初学者,当然,程杰的《大话设计模式》也是非常好的一本书,都可以拿过来当做一本工具书随时查看理解设计的奥妙。

      

      工厂模式

      这个模式的名字就已经告诉了我们它想要做什么,就是让我们构造出一个工厂,然后生产我们需要的东西,即生成对象。那么,为什么要构造一个工厂呢,为什么不直接在代码中直接 new 一个出来呢?

      想象这样一种情况:有时我们设计一类东西时,这一类又包含有许多的具体类,那么,当我们需要得到这些对象时,如果我们一个一个的 new 出来,就会显得很粗糙,而且如果构造这些对象时,需要进行一些必要的初始化,而这些初始化操作对于这一类对象都是相似的,那么,我们的代码中就会显得非常的冗余,在 new 之后会出现很多相似的初始化对象代码。

      这时,你就会想,有这样一个东西,我只需要告诉它,我需要那个对象,那么,它就会生成那个对象,而且我不需要考虑到它实际的实现细节。那么这个东西就叫做工厂。

      工厂模式分为三类:

      简单工厂模式,工厂模式,抽象工厂模式

      下面就分别对这三个模式进行介绍

      

      简单工厂模式

      这是最简单的工厂模式类型,一般的设计会出现三个类或接口:

      1> 抽象产品类或者产品接口

      2> 具体产品类

      3> 工厂类

      注:这里我想多说几句关于抽象类和接口的区别,抽象类和接口是非常相似的东西,大部分时候它是可以互相代替的,那么它们之间存在什么不同呢?我们从名字中可以看出一个是对一类对象的抽象,一个是类的接口。举一个例子就好像这样,人分为黄种人,白种人。。。,那么,对于人,我们需要设计出一个抽象类还是接口呢?应该设计成为抽象类,因为,它是对人类的抽象,所有的人都应该具有这个特征。接口呢,什么应该设计成为接口呢?就好像人的爱好一样,比如,游泳,台球,乒乓球(这些都是我的爱好,哈哈),它是后天养成的东西,是需要具体的实现的,所以,这些应该是设计成为接口,所以,一个黄种人的类就好像下面这样:

      public class YellowHuman extends Human implements Swimming, PingPang ...  { }

      好的,回到前面的简单工厂里面,说它简单,因为这个模式只需要实现一个工厂类就能生产出我们需要的产品,还是以人种的例子(“著名的”女娲造人)做出说明。

      女娲制造出各种人种,黄种人,白种人,黑种人,首先,人具有的共同特点构造出一个抽象类:

public abstract class __Q_Y_Human
{
	abstract void __Q_Y_Color();
	
	abstract void __Q_Y_Talk();
	
	public void __Q_Y_Sex()
	{
		System.out.println("every one has sex : man/woman...");
	}
}
      

      然后,各种人种需要实现这个抽象类,这里举例黄种人实现抽象类:

public class __Q_Y_YellowHuman extends __Q_Y_Human{

	@Override
	public void __Q_Y_Color() {
		// TODO Auto-generated method stub
		System.out.println("黄色皮肤。。。");
	}

	@Override
	public void __Q_Y_Talk() {
		// TODO Auto-generated method stub
		System.out.println("一般说的都是双字节。。。");
	}

}
      

      工厂类也很容易写出来,就好像下面这样:

public class __Q_Y_Factory
{
	/*制造一个黄种人*/
	public __Q_Y_YellowHuman __Q_Y_CreateYellowHuman()
	{
		return new __Q_Y_YellowHuman();
	}
	
	public __Q_Y_BlackHuman __Q_Y_CreateBlackHuman()
	{
		return new __Q_Y_BlackHuman();
	}
	
	public __Q_Y_WhiteHuman __Q_Y_CreateWhiteHuman()
	{
		return new __Q_Y_WhiteHuman();
	}
}
      当我们需要构造出一个人的对象时,只需要调用工厂中的方法就可以了,是不是比以前单纯的 new 出来要清晰的多了呢!

      不过,这样会产生出扩展问题,假如现在又需要添加一种新的人种 -- 红种人,怎么办呢?具体的人种对象实现起来很简单,继承那个抽象类就可以了,那么,工厂类呢?我们不得不修改工厂中的方法,需要新增加一个,也许你会说这样也不难呀,添加一个方法就可以了。不过,这仅仅是增加一种人,如果有很多种呢?同时,这也破坏了原来的代码结构。所以,一种对简单工厂模式的改进出现了 -- 工厂模式。
      这个改进了的模式比简单工厂模式好的地方在于它是建立一个抽象工厂,具体生产产品的工厂需要继承抽象工厂,实现具体的生产方法以生产需要的不同产品。

      所以,它的思想也是很简单的,我们首先需要看下抽象工厂的实现:

public abstract class __Q_Y_Factory {
	public abstract <T extends __Q_Y_Human> T __Q_Y_CreateHuman(Class<T> _c);
}
      这里,它很简单,只是写了一个泛型方法,我们限定它的返回类型和参数都是 Human 的子类,下面看看具体实现的工厂类:

public class __Q_Y_HumanFactory extends __Q_Y_Factory {
	@SuppressWarnings("unchecked")
	@Override
	public <T extends __Q_Y_Human> T __Q_Y_CreateHuman(Class<T> _c) {
		// TODO Auto-generated method stub
		__Q_Y_Human _human = null;
		
		try {
			/*这里就是反射的应用,即仅仅是利用类的名字就能构造它的对象*/
			_human = (__Q_Y_Human)Class.forName(_c.getName()).newInstance();
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("创建人失败了。。。");
		}
		
		return (T) _human;
	}
}
      可以看到,这个方法根据不同的参数(类名)就可以得到不同的人种了,当我们新增加一个人种的时候,只是需要写出表示那个人种的类就可以了,其他的都不需要改变。

      为方便看代码的结构,下面贴出以上方法的类图:

技术分享

      从上面的类图中可以看到,三类人都继承自 “人” 的抽象类,具体的工厂也是继承自工厂抽象类。

      下面介绍抽象工厂模式:

      抽象工厂模式与工厂模式的构造大致是一样的,它们的区别之处在于抽象两个字,抽象工厂模式的抽象程度要高于工厂模式,意思是抽象工厂的同一套接口能够得到不同类型的对象。

      人分为男和女,那么,代码中生产的人也需要分出性别来,如果依照上面的工厂接口我们没办法做到这一点,当然,表示人的类也是需要变化的,要有不同肤色的男人类,不同肤色的女人类。首先,我们需要看看人类的设计。

      第一层抽象类:

public abstract class __Q_Y_Human {
	
	public abstract void __Q_Y_Sex();
	
	public abstract void __Q_Y_Color();
}
      第二层抽象类:

public abstract class __Q_Y_YellowHuman extends __Q_Y_Human{

	public void __Q_Y_Color() {
		System.out.println("yellow human...");
	}
}
      第三层具体类(两个):

public class __Q_Y_MaleYellowHuman extends __Q_Y_YellowHuman{

	@Override
	public void __Q_Y_Sex() {
		// TODO Auto-generated method stub
		System.out.println("male yellow human...");
	}

}
public class __Q_Y_FamaleYellowHuman extends __Q_Y_YellowHuman{

	@Override
	public void __Q_Y_Sex() {
		// TODO Auto-generated method stub
		System.out.println("famale yellow human...");
	}

}
     

      这里就很明显了,我们只要构造一个抽象工厂能够 “生产” 不同类别的人就行了,抽象工厂的定义如下:

public abstract class __Q_Y_Factory {
	
	public abstract __Q_Y_Human __Q_Y_Create();
}

      从上面的例子中可以看到,工厂返回的只是 Human 类型的对象,不知道 Human 的肤色是什么,也不知道 Human 的性别是什么。这也就是抽象工厂的意思,它生产出来的对象更为抽象,抽象到可以表示不同的类型的对象。

      好吧,我们看下具体的实现方式是怎么样:

      生产黄种男性:

public class __Q_Y_FamaleFactory extends __Q_Y_Factory{

	@Override
	public __Q_Y_Human __Q_Y_Create() {
		// TODO Auto-generated method stub
		return new __Q_Y_FamaleYellowHuman();
	}

}
      生产黄种女性:

public class __Q_Y_MaleFactory extends __Q_Y_Factory{

	@Override
	public __Q_Y_Human __Q_Y_Create() {
		// TODO Auto-generated method stub
		return new __Q_Y_MaleYellowHuman();
	}

}

      当然,除了黄种人,黑种人,白种人都可以自己去实现加到这个模式中,为方便理解模式的构造,贴出抽象工厂模式实现的类图:

技术分享


      工厂模式(简单工厂模式,工厂模式,抽象工厂模式)是实际运用中最多的设计模式,所以,需要理解这种模式,并在实际的软件开发中尝试用这种设计模式构造容易理解的架构。


读秦小波《设计模式之禅》 -- 工厂模式