在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用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)的更多相关文章

  1. Swift 实现单例模式Singleton pattern的三种方法

    转自:点击打开链接 From my short experience with Swift there are three approaches to implement the Singleton ...

  2. 面向对象设计——抽象工厂(Abstract Factory)模式

    定义 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类.抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么.这样一来,客户就能从具体的产 ...

  3. JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)

    简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...

  4. python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)

    十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...

  5. 5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

    趁热打铁,紧跟着上一节的工厂方法模式.这一节介绍一下抽象工厂模式,以及分析俩个模式的不同 1.何为抽象模式? 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他 ...

  6. 设计模式——抽象工厂(Abstract Factory)

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类. ——DP UML类图 模式说明 抽象工厂与工厂方法在定义上最明显的区别是“创建一系列相关或相互依赖对象的接口”,由此可以看出抽象工 ...

  7. 设计模式——工厂方法(Factory Method)

    定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. ——DP UML类图 模式说明 抽象业务基类 实际业务类的公共基类,也是工厂要创建的所有对象的父类,这部分 ...

  8. Spring 通过工厂方法(Factory Method)来配置bean

    Spring 通过工厂方法(Factory Method)来配置bean 在Spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. ...

  9. 设计模式四: 抽象工厂(Abstract Factory)

    简介 抽象工厂模式是创建型模式的一种, 与工厂方法不同的是抽象工厂针对的是生产一组相关的产品, 即一个产品族. 抽象工厂使用工厂方法模式来生产单一产品, 单一产品的具体实现分别属于不同的产品族. 抽象 ...

随机推荐

  1. USACO 6.4 The Primes

    The PrimesIOI'94 In the square below, each row, each column and the two diagonals can be read as a f ...

  2. 使用ASP.NET MVC+Entity Framework快速搭建系统

    详细资料: http://www.cnblogs.com/dingfangbo/p/5771741.html 学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和 ...

  3. 基于 Laravel 开发博客应用系列 —— 设置 Linux/Mac 本地开发环境

    1.不同 Linux 发行版本的区别 不同的 Linux 发行版本之间有一些细微区别,尤其是包管理器:CentOS 和 Fedora 使用 yum 作为包管理器,而Ubuntu 使用  apt,在 O ...

  4. 统计无向图中三角形的个数,复杂度m*sqrt(m).

    统计无向图中三角形的个数,复杂度m*sqrt(m). #include<stdio.h> #include<vector> #include<set> #inclu ...

  5. spring4声明式事务—02 xml配置方式

    1.配置普通的 controller,service ,dao 的bean. <!-- 配置 dao ,service --> <bean id="bookShopDao& ...

  6. 关于php上传文件过大的表单回填

    也许标题有点绕口,有点无法让人理解.请原谅博主,语文学的不好,都赖体育老师. 问题场景重现:在某次迭代中,接到这样一个需求:当新建或编辑一个Bug(包含附件以及其他字段)上传附件过大时,退回到编辑页面 ...

  7. centos+uwsgi+nginx+python+django服务器安装配置

    1.ssh登录后使用fdisk –l查看需要格式化硬盘的名称: 2.运行fdisk /dev/vdb,对数据盘进行分区,按照提示,依次输入n,p,1,两次回车,wq,分区开始.(注意数据盘的名称,和阿 ...

  8. JS 常用库汇总收集

    本文不定期更新, 用于汇总记录一些看着 ok 的 JS 库. 库名 简介 项目地址 macy.js 仅 4 kb的 原生 流布局插件 http://macyjs.com/ Driver.js 仅 4 ...

  9. 洛谷.2619.[国家集训队2]Tree I(带权二分 Kruskal)

    题目链接 \(Description\) 给定一个无向带权连通图,每条边是黑色或白色.求一棵最小权的恰好有K条白边的生成树. \(Solution\) Kruskal是选取最小的n-1条边.而白边数有 ...

  10. php发送get、post请求的6种方法代码示例

    本文主要展示了php发送get.post请求的6种方法的代码示例,分别为使用file_get_contents .fopen.fsockopen.curl来发送GET和POST请求,代码如下: 方法1 ...