抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)
在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实例化这个对象,好处就是客户端并不知道这个实例化的对象的实际实现,从而可以将这个对象随意替换成我们需要的不同实现
工厂方法(Factory Method)
概念:定义一个用于创建对象的接口,让子类决定实例化哪个类.它使一个类的实例化延迟到其子类
结构图:
抽象工厂(Abstract Factory)
概念: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类.
结构图:
单例模式(Singleton Pattern)
概念: 保证一个类仅有一个实例,并提供一个访问它的全局访问点
结构图:
很长一段时间我都无法理解抽象工厂和工厂方法的区别,现在我的理解是
1. 抽象工厂是提供创建一组产品类的接口的一个类(工厂),它只提供创建这个类的接口,至于具体如何创建,创建的是这个类的什么子类,这些都不是抽象工厂关心的范畴,换句话说,我们在很多设计模式例子所看到的使用具体工厂继承抽象工厂来生成产品的例子,只是抽象工厂的其中一种实现,也就是说抽象工厂仅仅是定义了一组生产产品的接口,一个没有实现的抽象工厂仅仅定义了这样一组接口,是无法使用的.而生产的实现是需要依赖其他设计模式的,例如工厂方法,原型模式.按照我的理解,单纯的谈论抽象工厂,它应该只包含下面这样的定义
public abstract class ABFactory {
public abstract Product1 createProduct1();
public abstract Product2 createProduct2();
}
2. 在定义中我们看到AbstractFactory拥有具体的ConcreteFactory实现,这个实现的方式其实就是工厂方法,他将具体生产product的方法实现延迟到了子类
3. 为了生产产品,首先我们要获取工厂,而由于工厂的无状态性,往往会将工厂作为单例使用,所以我们创建和获取工厂的方法使用单例来实现
下面是一个例子
抽象工厂类
package factory; import product.Body;
import product.Head; import java.util.HashMap;
import java.util.Map; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-7-31
* Time: 下午11:32
* To change this template use File | Settings | File Templates.
*/
public abstract class ModuleFactory { // 对于抽象工厂而言,由于instance有多种实现
// 所以此处使用一个instanceMap存储所有的Factory实现
// 如果只有一个instance,那么多线程环境下我们将只能使用过一种类型的Factory
public static String CAT_MODULE_FACTORY = "cat_module_factory";
public static String DOG_MODULE_FACTORY = "dog_module_factory";
// 单例工厂列表
private static Map<String, ModuleFactory> instanceMap = new HashMap<String, ModuleFactory>();
static {
// 舍弃延迟加载,直接减给所有factory注册进Map里
// 好处是不要每增加一个具体工厂就去修改createFactory里的判断你条件
// 只需要在这个注册代码块里将新的工厂注册进去,而这个注册代码块可以
// 写在别的类或者配置文件里来实现,这样就达成了新增工厂和创建工厂解耦
instanceMap.put(CAT_MODULE_FACTORY, new CatModuleFactory());
instanceMap.put(DOG_MODULE_FACTORY, new DogModuleFactory());
} private static Object lockObj = new Object(); // 动态返回单例的工厂
public static ModuleFactory createFactory(String factoryType) {
if (factoryType == null)
throw new RuntimeException("Param factoryType cannot be null"); // 延迟实例化各不同该类型的工厂
// 舍弃延迟加载技术,则可以省去if条件判断
// if (instanceMap.get(factoryType) == null) {
// synchronized (lockObj) {
// if (instanceMap.get(factoryType) == null) {
// if (factoryType.equals(CAT_MODULE_FACTORY)) {
// instanceMap.put(CAT_MODULE_FACTORY, new CatModuleFactory());
// } else if (factoryType.equals(DOG_MODULE_FACTORY)) {
// instanceMap.put(DOG_MODULE_FACTORY, new DogModuleFactory());
// } else {
// throw new RuntimeException("FactoryType " + factoryType + " undefined");
// }
// }
// }
// } return instanceMap.get(factoryType);
} // 工厂方法
public abstract Head createHead();
public abstract Body createBody();
}
具体工厂类
package factory; import product.Body;
import product.CatBody;
import product.CatHead;
import product.Head; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-7-31
* Time: 下午11:36
* To change this template use File | Settings | File Templates.
*/
public class CatModuleFactory extends ModuleFactory {
@Override
public Head createHead() {
return new CatHead();
} @Override
public Body createBody() {
return new CatBody();
}
} package factory; import product.Body;
import product.DogBody;
import product.DogHead;
import product.Head; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-7-31
* Time: 下午11:36
* To change this template use File | Settings | File Templates.
*/
public class DogModuleFactory extends ModuleFactory {
@Override
public Head createHead() {
return new DogHead();
} @Override
public Body createBody() {
return new DogBody();
}
}
产品类
package product; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:24
* To change this template use File | Settings | File Templates.
*/
public abstract class Body {
public abstract void dance();
} package product; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:27
* To change this template use File | Settings | File Templates.
*/
public class CatBody extends Body {
@Override
public void dance() {
System.out.println("A caaat's body is dancing crazily!!");
}
} package product; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:27
* To change this template use File | Settings | File Templates.
*/
public class DogBody extends Body {
@Override
public void dance() {
System.out.println("A dooog's body is dancing!");
}
} package product; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:24
* To change this template use File | Settings | File Templates.
*/
public abstract class Head {
public abstract void eat();
} package product; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:29
* To change this template use File | Settings | File Templates.
*/
public class CatHead extends Head {
@Override
public void eat() {
System.out.println("A caaat's head is eating fast");
}
} package product; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:29
* To change this template use File | Settings | File Templates.
*/
public class DogHead extends Head {
@Override
public void eat() {
System.out.println("A dooog's head is eating");
}
}
测试类
import factory.CatModuleFactory;
import factory.DogModuleFactory;
import factory.ModuleFactory;
import product.Body;
import product.Head; /**
* Created with IntelliJ IDEA.
* User: zhenwei.liu
* Date: 13-8-1
* Time: 上午12:00
* To change this template use File | Settings | File Templates.
*/
public class Test { // 通过工厂解耦方法内animal实现
// 这个方法就是多态代码的实现
public static void act(ModuleFactory factory) {
Head head = factory.createHead();
Body body = factory.createBody();
head.eat();
body.dance();
} public static void main(String[] args) {
ModuleFactory factory = ModuleFactory.createFactory(ModuleFactory.CAT_MODULE_FACTORY);
act(factory);
factory = ModuleFactory.createFactory(ModuleFactory.DOG_MODULE_FACTORY);
act(factory);
}
}
输出
A caaat's head is eating fast
A caaat's body is dancing crazily!!
A dooog's head is eating
A dooog's body is dancing!
抽象工厂的优点和缺点
优点
1.分离具体类和客户端的耦合,客户端只需要根据Head和Body这种产品抽象类来编写代码,而具体实现则由具体的factory来决定(如act()方法)
2.易于替换产品系列,要使用不同的产品系列,只需要替换具体的factory即可(如act()方法)
3.可以保持产品系列的一致性,不会出现CatHead和DogBody这样的组合(至少基于工厂方法的抽象工厂是如此)
缺点
抽象工厂对新产品的支持度较差(无论是基于工厂方法还是基于原型),加入新加入了一个Foot的product,则需要在抽象工厂中加入抽象方法createFoot()并在所有的具体工厂中实现这个createFoot()方法.
工厂方法的优点和缺点
很大程度上工厂方法的优点和缺点与抽象工厂是类似的,因为工厂方法是抽象工厂的实现之一
优点
用户只需要针对抽象的产品类或接口进行编码,而不必关注具体实现类,达到与产品类解耦和多态的目的
缺点
工厂方法是一个产品-创建器的平行结构,每增加一个产品则需要增加一个创建器,应对变化的能力较差
单例模式的优点和缺点
优点
1.使用单例可以节省系统资源
2.可以严格控制对唯一实例的访问
3. GoF中文版写的优点全都没看懂....
缺点: 没看懂
抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)的更多相关文章
- Swift 实现单例模式Singleton pattern的三种方法
转自:点击打开链接 From my short experience with Swift there are three approaches to implement the Singleton ...
- 面向对象设计——抽象工厂(Abstract Factory)模式
定义 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类.抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么.这样一来,客户就能从具体的产 ...
- JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)
简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...
- python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)
十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...
- 5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式
趁热打铁,紧跟着上一节的工厂方法模式.这一节介绍一下抽象工厂模式,以及分析俩个模式的不同 1.何为抽象模式? 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他 ...
- 设计模式——抽象工厂(Abstract Factory)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类. ——DP UML类图 模式说明 抽象工厂与工厂方法在定义上最明显的区别是“创建一系列相关或相互依赖对象的接口”,由此可以看出抽象工 ...
- 设计模式——工厂方法(Factory Method)
定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. ——DP UML类图 模式说明 抽象业务基类 实际业务类的公共基类,也是工厂要创建的所有对象的父类,这部分 ...
- Spring 通过工厂方法(Factory Method)来配置bean
Spring 通过工厂方法(Factory Method)来配置bean 在Spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. ...
- 设计模式四: 抽象工厂(Abstract Factory)
简介 抽象工厂模式是创建型模式的一种, 与工厂方法不同的是抽象工厂针对的是生产一组相关的产品, 即一个产品族. 抽象工厂使用工厂方法模式来生产单一产品, 单一产品的具体实现分别属于不同的产品族. 抽象 ...
随机推荐
- Looksery Cup 2015 F - Yura and Developers 单调栈+启发式合并
F - Yura and Developers 第一次知道单调栈搞出来的区间也能启发式合并... 你把它想想成一个树的形式, 可以发现确实可以启发式合并. #include<bits/stdc+ ...
- spring websocket集群问题的简单记录
目录 前言 解决方案 代码示例 前言 最近公司里遇到一个问题,在集群中一些websocket的消息丢失了. 产生问题的原理很简单,发送消息的服务和接收者连接的服务不是同一个服务. 解决方案 用中间件( ...
- odoo基础数据加载
odoo 基础数据加载 这里介绍的odoo基础数据加载分两种方式,一种是演示数据加载,一种是默认数据加载,下面就是详细介绍 首先,当然是创建一个date文件夹 项目目录,右键自定义一个文件夹 XML数 ...
- 加密grub防止通过单用户模式破解root密码
(1).CentOS6 1)产生加密密码 [root@CentOS6 ~]# grub-md5-crypt Password: Retype password: $1$QPduF0$FNhzDUPQP ...
- 1014 Waiting in Line (30)(30 point(s))
problem Suppose a bank has N windows open for service. There is a yellow line in front of the window ...
- [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
显然有决策单调性,但由于逆序对不容易计算,考虑分治DP. solve(k,x,y,l,r)表示当前需要选k段,待更新的位置为[l,r],这些位置的可能决策点区间为[x,y].暴力计算出(l+r)/2的 ...
- [Luogu5162]WD与积木(多项式求逆)
不要以为用上Stirling数就一定离正解更近,FFT都是从DP式本身出发的. 设f[i]为i个积木的所有方案的层数总和,g[i]为i个积木的方案数,则答案为$\frac{f[i]}{g[i]}$ 转 ...
- HDU 1698 just a hook 线段树,区间定值,求和
Just a Hook Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1 ...
- BZOJ 1059: [ZJOI2007]矩阵游戏 匈牙利算法
1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2351 Solved: 1156 题目连接 http:// ...
- 移动端适配之REM
随着手机等移动设备的普及,移动端带来的流量已经不可忽视,一个网站不只是只有pc的页面就足够了,移动端的适配已经势在必行.但是移动设备种类繁多,屏幕尺寸也千奇百怪,能不能找到一种方式可以适配所有的手机屏 ...