设计模式之工厂模式(Factory Pattern)
一.什么是工厂模式?
1.“简单工厂模式”,Simple Factory Pattern
也就是常用的在Factory类中定义静态方法负责new对象的方式。
摘要中提到过“严格地说,这种被称为“简单工厂模式”的方式根本不能称之为“模式””,虽然静态工厂方法并不是真正的“设计模式”,但这种方式的应用也很广泛,也能带来一些好处,所以我们不能因为它不是“设计模式”就抛弃它。
2.工厂方法模式,Factory Method Pattern
是工厂模式的核心
定义一个抽象的“工厂方法”来负责new对象,由该类的扩展类来实现如何new的过程
这种方式成功分离了对象创建过程与对象行为(暂不做解释),确切地说是把对象创建“下放”到了子类。(注意这里的动词——“下放”)
3.抽象工厂模式,Abstract Factory Pattern
是对工厂方法模式的一种应用与扩展
把多个“工厂方法”封装在一个抽象工厂类中,以实现“new一组对象”的目的
二.一般方式(不用工厂模式)
我们来开一个小店卖衣服,首先需要ColthesStore类负责接收订单返回做好的衣服,ClothesStore类需要依赖Clothes类,毕竟要操作的具体对象是Clothes,ClothesStore中还要有做衣服的工序(制作、加工装饰。。)
那么我们的ClothesStore将是这样的:
package FactoryPattern; /**
* @author ayqy
* 不使用工厂模式,直接创建具体对象
*
*/
public class ClothesStore { String type;//定义衣服类型
Clothes clothes;//衣服对象 /**
* @author ayqy
* 定义内部类Clothes
*
*/
class Clothes{
String type;//类型
String desc;//描述
String cloth;//布料 public Clothes(String type, String desc, String cloth){
this.type = type;
this.desc = desc;
this.cloth = cloth;
} public String toString(){
return type+ "," + desc + "," + cloth;
}
} public ClothesStore(String type){
this.type = type;
} /**
* @return 返回未经装饰加工的衣服
*/
private Clothes createClothes(String type){
if(type.equals("外套")){
return new Clothes("外套", "一件好看的外套", "麻布");
}else if(type.equals("内衣")){
return new Clothes("内衣", "一件舒适的内衣", "棉布");
}else
return null;
} /**
* @return 返回做好的衣服
*/
public Clothes getClothes(){
clothes = createClothes(type);
decorate(clothes);//对衣服进行装饰 return clothes;
} private void decorate(Clothes clothes){
//给衣服添加装饰(图案、纹样等等)
System.out.println("精心装饰完毕,衣服变得更漂亮了");
}
}
P.S.代码中把Clothes定义为内部类,只是为了节省篇幅简化结构,效果一样
我们发现ClothesStore对Clothes有着很强的依赖(过分依赖“具体”可不是一件好事儿。。),一旦Clothes发生变化(如有了新的成员变量与成员函数),我们的ClothesStore可能就不得不跟着修改了,尤其是负责new衣服对象的部分:
/**
* @return 返回未经装饰加工的衣服
*/
private Clothes createClothes(String type){
if(type.equals("外套")){
return new Clothes("外套", "一件好看的外套", "麻布");
}else if(type.equals("内衣")){
return new Clothes("内衣", "一件舒适的内衣", "棉布");
}else
return null;
}
一旦有了新的type我们就要添加一个else if来应对变化
而且由于ClothesStore与具体的Clothes类绑定在一起,导致ClothesStore不易于扩展,很难复用
三.“简单工厂模式”
把createClothes方法移动到ClothesFactory中作为一个静态工厂方法,就像这样:
package FactoryPattern.SimpleFactoryPattern; /**
* @author ayqy
* 定义静态工厂方法
*
*/
public class ClothesFactory {
/**
* @return 返回未经装饰加工的衣服
*/
public static Clothes createClothes(String type){
if(type.equals("外套")){
return new Clothes("外套", "一件好看的外套", "麻布");
}else if(type.equals("内衣")){
return new Clothes("内衣", "一件舒适的内衣", "棉布");
}else
return null;
}
}
P.S.这次必须把Clothes拿出来作为一个独立的类了(内部类无法访问),除此之外,ClothesStore中的getClothes方法也要做相应改变。。不要在意这些细节
应用简单工厂模式之后,我们确实把new对象的部分独立出来了,这样做的好处是:
当Clothes发生变化时,我们可以在ClothesFactory中直接修改create方法,而不是在ClothesStore的长篇代码中寻找Create部分
而且与之前的“一般方式”对比,代码几乎没有发生什么变化,很容易把之前的代码改成应用简单工厂模式之后的代码,所以很多开发人员喜欢这种方式
-------
“简单工厂模式”并不是真正的工厂模式,它的优势也是极其有限的,不过没关系,我们还有工厂方法模式,这次是货真价实的工厂模式
四.工厂方法模式
定义抽象的“工厂方法”,负责具体实现,全新的ClothesStore将是这样的:
package FactoryPattern.FactoryMethodPattern; /**
* @author ayqy
* 使用工厂方法模式,定义抽象的工厂方法来new产品
*
*/
public abstract class ClothesStore { String type;//定义衣服类型
Clothes clothes;//衣服对象 public ClothesStore(String type){
this.type = type;
} //定义工厂方法,由扩展类来实现具体制作细节
public abstract Clothes createClothes(String type); /**
* @return 返回做好的衣服
*/
public Clothes getClothes(){
clothes = createClothes(type);
decorate(clothes);//对衣服进行装饰 return clothes;
} private void decorate(Clothes clothes){
//给衣服添加装饰(图案、纹样等等)
System.out.println("精心装饰完毕,衣服变得更漂亮了");
}
}
我们发现ClothesStore变成Abstract的了,里面封装了衣服的制作工序以及实现细节,但并没有实现Create过程
下一步是要扩展ClothesStore类,实现具体Create细节,就像这样:
package FactoryPattern.FactoryMethodPattern; /**
* @author ayqy
* 扩展ClothesStore,实现具体制作细节
*
*/
public class DefaultClothesStore extends ClothesStore{ public DefaultClothesStore(String type) {
super(type);
} /*
* 实现具体制作细节
*/
@Override
public Clothes createClothes(String type) {
if(type.equals("外套")){
return new Clothes("外套", "一件好看的外套", "麻布");
}else if(type.equals("内衣")){
return new Clothes("内衣", "一件舒适的内衣", "棉布");
}else
return null;
}
}
嗯,现在我们已经成功应用工厂方法模式了,让我们来看看相比之前的简单工厂模式,这个货真价实的工厂模式有哪些特点
1.同样实现了new对象的具体过程与对象行为的分离,但不同的是我们是利用继承(扩展)来实现的,也就是开篇提到的“下放”(把具体实现放到更低的类层次上)
2.每一个具体Store都必须实现自己的Create细节,但同时又可以利用基类Store的制作工艺(decorate方法等等)
3.一个抽象的工厂方法轻松实现了工厂模式(甚至Factory自始至终根本没有出现,但我们确实已经实现了“工厂”,不是吗?)
五.抽象工厂模式
抽象工厂模式是对上一种方式的扩展,在上面我们只能Create一个产品,但很多时候我们需要Create一组产品,比如衣服的原料,包括布料、染料、线、纽扣等等,这时候就需要应用抽象工厂模式来实现:
package FactoryPattern.AbstractFactoryPattern; /**
* @author ayqy
* 定义原料工厂
*
*/
public abstract class ResourcesFactory {
public abstract Cloth getCloth();//获取布料
public abstract Color getColor();//获取染料
public abstract Button getButton();//获取纽扣
//需要的其它工厂方法
}
抽象工厂中的类型都是自定义接口,例如:
package FactoryPattern.AbstractFactoryPattern; /**
* @author ayqy
* 定义Cloth接口
*/
public interface Cloth {
//属性
//行为
}
有了原料工厂,那么ClothesStore也要做相应的改变来适应这种新的结构:
package FactoryPattern.AbstractFactoryPattern; /**
* @author ayqy
* 扩展ClothesStore,实现具体制作细节
*
*/
public class DefaultClothesStore extends ClothesStore{ public DefaultClothesStore(String type, ResourcesFactory res) {
super(type, res);
} /*
* 实现具体制作细节
*/
@Override
public Clothes createClothes(String type) {
if(type.equals("外套")){
//获取所需原料
Cloth cloth = res.getCloth();
Color color = res.getColor();
Button button = res.getButton();
//制作衣服
return new Clothes("外套", color.toString() + button.toString(), cloth.toString());
}else if(type.equals("内衣")){
//获取所需原料
Cloth cloth = res.getCloth();
Color color = res.getColor();
Button button = res.getButton();
//制作衣服
return new Clothes("内衣", color.toString() + button.toString(), cloth.toString());
}else
return null;
}
}
现在创建Store对象时需要一个具体ResourcesFactory参数(具体的原料工厂实现了所有的getXXX工厂方法),具体的Store只负责具体制作过程,需要什么原料都可以从ResourceFactory中取得,具体Store做衣服后,由Store基类负责工艺加工(decorate方法等等),最后由具体的Store返回精加工完毕的衣服
整个结构很疏松,低耦合,易扩展
-------
除此之外,还有必要提及一个OO设计原则——“依赖倒置原则”
通过观察类结构我们可以发现:
高层组件Store依赖Clothes,同时低层组件ResourcesFactory也依赖Clothes(这就是“依赖倒置”,即低层组件反过来依赖高层组件,同时高低层组件都依赖抽象)
这样的设计有着极易扩展的优势(抽象意味着可扩展。。)
六.总结
其实开篇第一部分就是总结,这里要强调的是:事物都有两面性,一个好的东西必然存在缺点,设计模式也不例外。
抽象工厂模式看起来真的不错,但是也存在致命的缺点:多级抽象引起的结构复杂化问题
设计模式之工厂模式(Factory Pattern)的更多相关文章
- python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)
十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...
- 【设计模式】工厂模式 Factory Pattern
1)简单工厂(不是模式) 简单工厂只是一种变成习惯,并非23种设计模式之一. 简单工厂提供将实例话那种类型留给运行时判断,而非编译时指定.简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一个类的 ...
- JAVA设计模式之工厂模式—Factory Pattern
1.工厂模式简介 工厂模式用于对象的创建,使得客户从具体的产品对象中被解耦. 2.工厂模式分类 这里以制造coffee的例子开始工厂模式设计之旅. 我们知道coffee只是一种泛举,在点购咖啡时需要指 ...
- 设计模式 - 工厂模式(factory pattern) 具体解释
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u012515223/article/details/27081511 工厂模式(factory pa ...
- 设计模式之工厂模式(Factory)
设计模式的工厂模式一共有三种:简单工厂模式,工厂模式,抽象工厂模式 简单工厂模式原理:只有一个工厂类,通过传参的形式确定所创建的产品对象种类 代码如下: #include <stdio.h> ...
- 23种设计模式--工厂模式-Factory Pattern
一.工厂模式的介绍 工厂模式让我们相到的就是工厂,那么生活中的工厂是生产产品的,在代码中的工厂是生产实例的,在直白一点就是生产实例的类,代码中我们常用new关键字,那么这个new出来的实例 ...
- 创建型模式篇(工厂模式Factory Pattern)
一.工厂模式(Factory Pattern) 1.定义: 在软件系统,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.提供一种封 ...
- java_设计模式_工厂模式_Factory Pattern(2016-08-04)
工厂模式主要是为创建对象提供了接口.工厂模式按照<Java与模式>中的提法分为三类: (1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory ...
- 设计模式之工厂模式(Factory模式)
在面向对象系统设计中经常遇到以下两类问题: 1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口.这样我们可以通过声明一个指向基类的 ...
- 设计模式~简单工厂模式(Factory)
简单工厂模式Simple Factory根据提供给它的数据,返回一个类的实例.通常它返回的类都有一个公共的父类(或者接口对象). 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类 ...
随机推荐
- Ubuntu cd
查看目录文件内容 ./ or filename/file.* cd 返回用户主目录 ~,,,,,/home/user cd ..不管用 cd / 返回用户根目录 root
- 【校招面试 之 C/C++】第20题 C++ STL(二)之Vector
1.vector的动态增长 当添加元素时,如果vector空间大小不足,则会以原大小的两倍另外配置一块较大的新空间,然后将原空间内容拷贝过来,在新空间的内容末尾添加元素,并释放原空间.vector的空 ...
- python之多并发socket
先看socket多并发的服务端的代码,这里是用多线程实现的多并发socketserver import socketserver # socketserver有四个基本的类,后两个不常用,这4个类处理 ...
- 带最小值操作的栈 · Min Stack
[抄题]: 实现一个带有取最小值min方法的栈,min方法将返回当前栈中的最小值. 你实现的栈将支持push,pop 和 min 操作,所有操作要求都在O(1)时间内完成. [思维问题]: [一句话思 ...
- sphinx文档
Navigation index modules | Sphinx主页 | 文档 » 下载 目前版本: 1.2 获得 Sphinx 从 Python Package Index, 或者使用如下命令安装 ...
- Alien::BatToExeConverter 模块应用
## DOS 下批量任务转换成exe二进制可执行文件 Convert a DOS Batch Script to an Executable Alien::BatToExeConverter::ba ...
- pyspider示例代码六:传递参数
传递参数 示例一 #!/usr/bin/env python # -*- encoding: utf- -*- # vim: ts= sts= ff=unix fenc=utf8: # Created ...
- Android framework层实现实现wifi无缝切换AP
http://www.linuxidc.com/Linux/2013-12/93476.htm Android市场上有一款叫Wifijumper的软件,实现相同ssid的多个AP之间根据wifi信号的 ...
- 2018.10.18 bzoj1185: [HNOI2007]最小矩形覆盖(旋转卡壳)
传送门 不难看出最后的矩形一定有一条边与凸包某条边重合. 因此先求出凸包,然后旋转卡壳求出当前最小矩形面积更新答案. 代码: #include<bits/stdc++.h> #define ...
- hadoop学习笔记(四):hdfs常用命令
一.hadoop fs 1.创建目录 [root@master hadoop-]# hadoop fs -mkdir /testdir1 [root@master hadoop-]# hadoop f ...