【设计模式】工厂模式详解

前言

现在大三下期了,正在学习设计模式。

感觉在安卓开发中,有很多地方都可以用到工厂模式。于是写了这篇文档。

为暑假的实习做好准备。(话说我现在还不知道去哪里实习呢T_T)

博主只是一大三学生,文章难免有不足之处吗,欢迎批评指正(^_^)


正文

转载请注明出处: http://blog.csdn.net/h28496/article/details/44258601

发 表 时 间: 2015年3月14日


为什么要有工厂模式

为了便于说明,我们自定义两个概念(和数据库中的类似):

①  操作:单独一个语句的执行。

②  过程:多个操作在一起执行,完成某个特定的任务。

下面是一段引用自网络的解释:

在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。在这些情况,新对象的建立就是一个 “过程”,不仅是一个操作.

创建一个String类的对象比较简单,只需要一句话(一个操作)就可以完成。如:String s = new String(“12346”);

但有时候我们创建一个其他类的对象时就比较复杂了。有可能在生成这个复杂对象之前需要生成一些辅助功能的对象。例如:

创建一个人物模型,我们需要先创建好鼻子、眼睛、耳朵、四肢、衣物。即创建一个人物模型时,需要一系列的操作(一个过程)才能完成。如果我们需要在不同的代码段中频繁的创建人物模型时,上述一大段代码可能会到处出现。这不利于往后对代码的修改和维护。

另外,使用new操作符不符合开闭原则(对扩展开放,对修改封闭)。关于开闭原则,请参考百度百科词条:开闭原则

因此,使用工厂模式的原因大致有两个:

①  只用一句话就创建一个实例对象,而不用去关心具体创建的过程。

②  降低代码的耦合度,使代码在以后的修改、维护、扩展中更加方便。


初步了解工厂模式的好处

如果没有工厂模式

用户想要一台手机,于是自己造了一个cpu、自己造内存、自己造……,最后合在一起造出了手机。

如果有很多个用户想要,那他们都得自己造自己的手机。这浪费了很多的模具,而且效率不高。(非批量化生产)

后来这些用户都要换成iPhone8,于是他们各自又重新造iPhone8的手机部件。      


如果有工厂模式

用户想要一台手机,于是告诉工厂“我要手机”。工厂给他一台手机。

如果有多个客户想要手机,工厂都可以给他们。这时,工厂的模具是多次使用的,没有浪费,而且效率较高。(批量化生产)

后来这些用户都要换成iPhone8,于是工厂只重新修改了一次模具,所有的用户都用上了iPhone8。


工厂模式详解

简单工厂模式(Simple Factory)

什么是简单工厂模式

用户想要手机,不用自己去造手机,只需告诉工厂要什么手机,工厂就给他什么手机。如:

用户1买手机,说:“我要iPhone6 16G版。”工厂给了他16G版;

用户2买手机,说:“我要iPhone6 64G版。”工厂给了他64G版;

用户3买手机,说:“我要iPhone6 128G版。”工厂给了他128G版。

可以理解为:简单工厂模式就是一个switch…case组合,需要根据参数判断返回哪种产品。


代码示例

代码结构:

     


    IPhone6.java

package zhp.factory.简单工厂模式.产品;

public abstract class IPhone6 {
	
}

    IPhone6_16G.java    

package zhp.factory.简单工厂模式.产品;

public class IPhone6_16G extends IPhone6 {
	
	public IPhone6_16G(){
		System.out.println("创建IPhone6_16G成功!");
	}
	
}
    IPhone6_32G.java
package zhp.factory.简单工厂模式.产品;

public class IPhone6_32G extends IPhone6 {
	
	public IPhone6_32G(){
		System.out.println("创建IPhone6_32G成功!");
	}
	
}
    IPhone6_64G.java
package zhp.factory.简单工厂模式.产品;

public class IPhone6_64G extends IPhone6 {
	
	public IPhone6_64G(){
		System.out.println("创建IPhone6_64G成功!");
	}
	
}
    Factory.java
package zhp.factory.简单工厂模式.工厂;

import zhp.factory.简单工厂模式.产品.IPhone6;
import zhp.factory.简单工厂模式.产品.IPhone6_16G;
import zhp.factory.简单工厂模式.产品.IPhone6_32G;
import zhp.factory.简单工厂模式.产品.IPhone6_64G;

public class Factory {
	
	public IPhone6 createPhone(String type){
		switch(type){
		case "16G":
			return new IPhone6_16G();
			
		case "32G":
			return new IPhone6_32G();
			
		case "64G":
			return new IPhone6_64G();
		}
		return null;
	}
	
}
    Main.java
package zhp.factory.简单工厂模式;

import zhp.factory.简单工厂模式.产品.IPhone6;
import zhp.factory.简单工厂模式.工厂.Factory;


public class Main {

	@SuppressWarnings("unused")
	public static void main(String[] args) {
		Factory factory = new Factory();		
		IPhone6 iphone16G = factory.createPhone("16G");
		IPhone6 iphone32G = factory.createPhone("32G");
		IPhone6 iphone64G = factory.createPhone("64G");
	}

}

简单工厂模式的组成

①  一个工厂类:根据不同情况创建不同的手机

②  一个抽象产品类:在这个例子中是iPhone这个大类。在java中一般用抽象类或者接口实现。

③  多个具体产品类:在这个例子中是iPhone 不同容量的版本。它们都继承/实现了抽象产品类。


工厂方法模式(Factory Method)

简单工厂模式的不足

用简单工厂模式时,有100个型号的手机,就有100个case。如果要添加iPhone6 Plus 16G/64G/128G这3个版本,就得再添加3个case。可以看出,简单工厂模式虽然比没有工厂方便,但依然存在如下问题:

①  修改起来还是麻烦,需要在一大堆case中修改;

②  不符合开闭性原则。不方便扩展,也没有对修改封闭。

 

什么是工厂方法模式

为了解决简单工厂模式的不足,又有了工厂方法模式。

定义:定义一个创建产品对象的抽象工厂,将实际创建工作推迟到抽象工厂的子类当中。

抽象工厂有多个子工厂,每个子工厂只生产一个特定的产品。每当新添加一个产品时,不必去修改之前存在的那些工厂,只需新建一个子工厂就行。这可以使系统在不修改具体工厂角色的情况下引进新的产品。

这样就对修改进行了封闭,同时也保留了扩展性。如图:


 

代码示例

代码结构:

     

“产品”包里面的四个类和简单工厂类一致,此处不再重复。

Factory.java

package zhp.factory.工厂方法模式.工厂;

import zhp.factory.工厂方法模式.产品.IPhone6;

public abstract class Factory {
	public abstract IPhone6 createPhone();
}
Factory_16G.java
package zhp.factory.工厂方法模式.工厂;

import zhp.factory.工厂方法模式.产品.IPhone6;
import zhp.factory.工厂方法模式.产品.IPhone6_16G;

public class Factory_16G extends Factory {

	@Override
	public IPhone6 createPhone() {
		return new IPhone6_16G();
	}

}

Factory_32G.java

package zhp.factory.工厂方法模式.工厂;

import zhp.factory.工厂方法模式.产品.IPhone6;
import zhp.factory.工厂方法模式.产品.IPhone6_32G;

public class Factory_32G extends Factory {

	@Override
	public IPhone6 createPhone() {
		return new IPhone6_32G();
	}

}
Factory_64G.java
package zhp.factory.工厂方法模式.工厂;

import zhp.factory.工厂方法模式.产品.IPhone6;
import zhp.factory.工厂方法模式.产品.IPhone6_64G;

public class Factory_64G extends Factory {

	@Override
	public IPhone6 createPhone() {
		return new IPhone6_64G();
	}

}

Main.java

package zhp.factory.工厂方法模式;

import zhp.factory.工厂方法模式.产品.IPhone6;
import zhp.factory.工厂方法模式.工厂.Factory;
import zhp.factory.工厂方法模式.工厂.Factory_16G;

public class Main {

	@SuppressWarnings("unused")
	public static void main(String[] args) {
		Factory factory = new Factory_16G();
		IPhone6 iPhone6 = factory.createPhone();
		
		// 增加一种机型,只需增加一个工厂。这里写成了匿名类的形式。实际维护中,这里应该是新建一个类。
		Factory factory128 = new Factory() {
			
			@Override
			public IPhone6 createPhone() {
				return new IPhone6_128G();
			}
			
		};
		
		IPhone6 iPhone128 = factory128.createPhone();
		
	}

}

class IPhone6_128G extends IPhone6{
	public IPhone6_128G(){
		System.out.println("128G的Iphone6已创建!");
	}
}


工厂方法模式的组成

①  一个抽象工厂类:工厂的总厂。是其他子工厂的父类,所有其他子工厂都得继承这个类。在java中一般是个抽象类或者接口。

②  多个具体工厂类:子工厂。他们继承自抽象工厂,用于创建具体的产品。

③  一个抽象产品类:同简单工厂模式。

④  多个具体产品类:同简单工厂模式。

注:简单工厂模式是工厂方法模式的特例。


抽象工厂模式(Abstract Factory)

抽象工厂模式的定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。只看定义比较难理解。

产品等级和产品族

理解抽象工厂模式之前,先了解一下这两个概念:

 ①  产品等级      ②  产品族

请看下面这张相图(不要在意iPhone6没有32G这种细节):


共有三个产品类,分别是(在这里,你可以把它们三个看成是继承了抽象手机类的三个子类,也可以看成是三个无关联的产品类。推荐后面一个,因为看成前者就更像工厂方法模式而不是抽象工厂模式了):

魅族MX4类、iPhone6类、Galaxy6类

这三个类分属是3个不同的产品等级结构。

内存也有三个类:16G、32G、64G,这三个类属于产品族。

看完可能会有这个疑问:为什么内存大小是产品族,而手机品牌是产品等级?产品族和产品等级可以互换吗?

我的看法:产品等级是物体,产品族是物体的属性。

我们可以说“这台iPhone6手机的属性“内存”是16G。”但是不能说“这个16G内存的属性“手机”是iPhone6。”

手机有属性“内存大小”,但是内存没有属性“手机类型”。

这里有一段来自网络的解释:

等级结构是抽象的,是一个概念,最好不要带属性,比如说猫,但是你没法指定哪一只猫;产品族是相对具体的,比如说白猫,就比猫更具体;当然你要把白猫放到等级结构也无所谓,但是白猫就属于比较具体的“概念”了,因为它带有比较具体的属性,所以我觉得放到抽象工厂里面并不合适,因为在具体工厂中要给他赋予区别于其他产品的属性。比如说,你把“猫”放到具体工厂,而把“白”放到抽象工厂,那么“猫”就属于“白”的属性了,至少我觉得很奇怪……

猫有属性“颜色”,但是颜色没有属性“动物类型”。

 

工厂方法模式的不足

如上面那张图所示,共有9种手机。如果使用工厂方法来做,需要建立一个抽象的工厂类PhoneFactory。然后再用9个子工厂类去实现它。

注意数量是9个!这9个子工厂的关系是并列的。即只有一个级。如图:


如果我们要再添加一个128G的版本怎么办?还得再写3个子工厂去实现,总共就有12个子工厂。发现问题了吗?

每增加一个新的内存配置就得增加N个子工厂类。(N是手机类型数量)

 

什么是抽象工厂模式

如果我们把内存和手机单独拿出来看呢?这样就有了两种产品。如图:


我们把不同的手机作为不同的产品,把不同的内存视为不同的产品族。

每一个产品族对应一个子工厂,就有了如下这张图(为了看起来更简洁,这里省去了三星手机和32G版本的手机):


在这个例子中,只有两个产品族:16G版本 和 64G版本。如果有多个产品族,就需要有多个子工厂,每个子工厂负责一个产品族。例如:如果还有32G版本的产品,只需再添加一个“32G版本工厂”即可。

我们再来看一下另外一个农场系统的例子(这是百度百科词条:抽象工厂模式里的一个例子)。问题的描述参见词条,这里只把关系图画出来:

 

代码示例

代码结构:

       


MX4.java

package zhp.factory.抽象工厂模式.产品.魅族产品;

public abstract class MX4 {

}
MX4_16G.java (MX4_32G.java.MX4_64G.java类似,后面略过)
package zhp.factory.抽象工厂模式.产品.魅族产品;

public class MX4_16G extends MX4 {
	
	public MX4_16G(){
		System.out.println("16G版本的MX4已被创建!");
	}
	
}
IPhone6.java
package zhp.factory.抽象工厂模式.产品.苹果产品;

public abstract class IPhone6 {
	
}
IPhone6_16G.java(Iphone_32G.java.Iphone_64G.java类似,后面略过)
package zhp.factory.抽象工厂模式.产品.苹果产品;

public class IPhone6_16G extends IPhone6 {
	
	public IPhone6_16G(){
		System.out.println("创建IPhone6_16G成功!");
	}
	
}
AbstractFactory.java
package zhp.factory.抽象工厂模式.工厂;

import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4;

public abstract class AbstractFactory {
	public abstract MX4 createMX4();
	public abstract IPhone6 createIphone6();
}
Factory_16G.java
package zhp.factory.抽象工厂模式.工厂;

import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6;
import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6_16G;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4_16G;

public class Factory_16G extends AbstractFactory {

	@Override
	public MX4 createMX4() {
		return new MX4_16G();
	}

	@Override
	public IPhone6 createIphone6() {
		return new IPhone6_16G();
	}

}
Factory_32G.java
package zhp.factory.抽象工厂模式.工厂;

import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6;
import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6_32G;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4_32G;

public class Factory_32G extends AbstractFactory {

	@Override
	public MX4 createMX4() {
		return new MX4_32G();
	}

	@Override
	public IPhone6 createIphone6() {
		return new IPhone6_32G();
	}

}
Main.java
package zhp.factory.抽象工厂模式;

import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6;
import zhp.factory.抽象工厂模式.产品.苹果产品.IPhone6_64G;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4;
import zhp.factory.抽象工厂模式.产品.魅族产品.MX4_64G;
import zhp.factory.抽象工厂模式.工厂.AbstractFactory;
import zhp.factory.抽象工厂模式.工厂.Factory_16G;

public class Main {
	@SuppressWarnings("unused")
	public static void main(String[] args){
		AbstractFactory factory_16 = new Factory_16G();
		MX4 mx4_16G = factory_16.createMX4();
		IPhone6 iphone6_16G = factory_16.createIphone6();
		
		// 如果新增一个64G版本的
		// 同样这里也用的是匿名类,在实际开发中这里应该是单独一个类
		AbstractFactory factory_64G = new AbstractFactory() {
			
			@Override
			public MX4 createMX4() {
				return new MX4_64G();
			}
			
			@Override
			public IPhone6 createIphone6() {
				return new IPhone6_64G();
			}
		};
	
		// 利用扩展的新工厂创建新产品
		MX4 mx4_64G = factory_64G.createMX4();
		IPhone6 iphone6_64G = factory_64G.createIphone6();
	}
}

抽象工厂模式的组成

①  一个抽象工厂类。

②  多个具体工厂类。

③  多个抽象产品类。

④  多个具体产品类。



三种工厂模式的特点和区别

简单工厂

工厂可以创建同一系列的产品,产品的接口一致,但工厂就要根据参数进行判断到底创建哪种产品。

卖早饭的张婆婆:可以做茶叶蛋,包子,稀饭

 

工厂方法

可以有多种子工厂,所有子工厂有共同的接口(抽象工厂),一个子工厂只能产生一种产品,比起简单工厂,工厂方法就不需要判断,耦合度低了不少。

刘老板:只卖包子的包子铺,只卖稀饭的稀饭庄。

 

抽象工厂

可以生产不同的产品,但这些产品又有某种相关性。

饮料店老板:可乐系列产品、咖啡系列产品,每种系列产品又分小杯、中杯、大杯。

上述三个例子源自csdn用户Patrick000的评论。

 

工厂方法模式和抽象工厂模式的比较

工厂方法模式

一个抽象产品类,可以派生出多个具体产品类。  

一个抽象工厂类,可以派生出多个具体工厂类。  

每个具体工厂类只能创建一个具体产品类的实例。

 

抽象工厂模式

多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。

一个抽象工厂类,可以派生出多个具体工厂类

每个具体工厂类可以创建多个具体产品类的实例。

   

区别

工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。  

工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

该比较源自百度知道king_wxw的回答,略作修改。

 

三种模式的递进关系




源代码下载

http://download.csdn.net/detail/h28496/8504171







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值