在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用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)
简介 抽象工厂模式是创建型模式的一种, 与工厂方法不同的是抽象工厂针对的是生产一组相关的产品, 即一个产品族. 抽象工厂使用工厂方法模式来生产单一产品, 单一产品的具体实现分别属于不同的产品族. 抽象 ...
随机推荐
-
一步步搭建自己的博客 .NET版(2、评论功能)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
-
启动Hive时出现的问题
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.RuntimeException: Unable to i ...
-
EI Index
Journal of Software (JoS). China. [link]
-
Python错误、调试和测试
try: print('try...') r = 10 / int('a') print('result:', r) except ValueError as e: print('ValueError ...
-
PKUSC 模拟赛 day2 上午总结
今天上午考得不是很好,主要还是自己太弱QAQ 开场第一题给的图和题意不符,搞了半天才知道原来是走日字形的 然后BFS即可 #include<cstdio> #include<cstr ...
-
Java多线程:线程间通信之volatile与sychronized
由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信. Java为线程间通信提供了三个相关的关键字volatile, synchronized ...
-
docker国内镜像源
https://www.daocloud.io/mirror curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http ...
-
C++ 虚函数的两个例子
1. 第一个例子是朋友告诉我Qt中的某个实现 1 #include <iostream> 2 3 // Qt中的某个实现 4 class A{ 5 public: 6 A() = defa ...
-
hbuilder真机调试时,手机端无法连接电脑测试的处理办法
首先保证手机端与电脑处在同一网段 关闭电脑防火墙 电脑服务端需要配置iis网站,同时在hbuilder的manifest.json 配置与iis网站ip一致的url
-
【lintcode13】字符串查找
问题: 对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始).如果不存在,则返回 -1. 样例:如果 ...