抽象工厂(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)
简介 抽象工厂模式是创建型模式的一种, 与工厂方法不同的是抽象工厂针对的是生产一组相关的产品, 即一个产品族. 抽象工厂使用工厂方法模式来生产单一产品, 单一产品的具体实现分别属于不同的产品族. 抽象 ...
随机推荐
- 继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类。 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 (3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承。 (4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。 分析以上程
继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法.(3)子类中定义的成员变量和父类中定义的 ...
- 手工释放linux内存------/proc/sys/vm/drop_cache
当在Linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching.这个问题,貌似有不少人在问,不过都没有看到有什么很好解决的办法.那么我来谈谈这个问题 ...
- Asp.Net Core2.0 WebAPI 使用Swagger生成漂亮的接口文档
1.引用NuGet: Swashbuckle.AspNetCore.Swagger Swashbuckle.AspNetCore.SwaggerGen 或 <PackageReference I ...
- 004 Numpy
一:Numpy介绍 1.简介 Numerical Python 就是数值python包,是python进行科学计算的一个基础包,因此要更好的理解与掌握python科学计算包,尤其是pandas,需要先 ...
- CI框架中site_url()和base_url()的区别
背景:在使用CI框架的使用经常碰到跳转和路径方面的问题,site_url()和base_url()很容易混淆,下面来说说他们的区别! 假如你config文件里面的base_url和index_page ...
- 我们不能把JavaScript作为一个全功能的编程语言。它缺乏以下重要特征
客户端JavaScript不允许读或写文件.这已被保存的安全原因. JavaScript不能用于网络的应用,因为没有这样的支持. JavaScript没有任何多线程或多处理器的能力.
- Redis 服务器命令
1.BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作 2.BGSAVE 在后台异步保存当前数据库的数据到磁盘 3.CLIENT KILL [ip:port ...
- UVA1378 A funny stone game
博弈论. 就是有一堆石子你拿走一堆中的一个,然后再向后面两堆中加两个问胜负 i<j<=k 所以我们可以直接通过sg函数计算,考虑问题的奇偶性,如果这一位是奇的我们才考虑,偶的可以模仿 然后 ...
- [xsy2913]enos
题意:一棵树,点有$0,1,2$三种颜色,支持路径修改颜色和查询点所在同色连通块的大小 lcm太可怕了,于是去问了sk,得到一个优质做法 考虑lct维护子树信息,$vs_{x,i}$为$x$的虚儿子中 ...
- Java日常错误及需要注意细节,持续更新......
记录日常工作中一些容易被忽视的错误及细节,持续更新...... 一.问题:HashMap<Long, String>中,用get(Integer key)取不到值 Map<Long, ...