LZ想把简单工厂模式、工厂方法模式和抽象工厂模式整理到一篇博文当中,由浅入深,应该能方便理解和记忆,话不多说,进入正题。

一、简单工厂模式

  定义:从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

  总结成一句话就是,由一个工厂对象决定创建出哪一种产品类的实例。下面是百度百科中简单工厂模式的类图。

  可以看出,上面总共有三种类,一个是工厂类Creator,一个是产品接口IProduct,一个是具体的产品类,例如产品A和产品B,这之中,工厂类负责整个创建产品的逻辑判断,所以为了使工厂类能够知道我们需要哪一种产品,我们需要在创建产品时传递一个参数给工厂类,去表明我们想要创建哪种产品。下面我们将类图翻译成java代码。

  首先是产品接口。

public interface IProduct {public void method();
}

  接下来是具体的产品类。

public class ProductA implements IProduct{public void method() {System.out.println("产品A方法");}}

public class ProductB implements IProduct{public void method() {System.out.println("产品B方法");}}

  最后是工厂类。

public class Creator {private Creator(){}public static IProduct createProduct(String productName){if (productName == null) {return null;}if (productName.equals("A")) {return new ProductA();}else if (productName.equals("B")) {return new ProductB();}else {return null;}}
}

  我们测试一下。

public class Client {public static void main(String[] args) {IProduct product1 = Creator.createProduct("A");product1.method();IProduct product2 = Creator.createProduct("B");product2.method();}
}

  测试结果。

  以上就是简单工厂模式的样子,这个模式有个缺点,如果新加一种产品类,则Creator类的代码要相应改动,而工厂方法模式就很好的遵守了开闭原则,即对修改关闭,对扩展开放。

二、工厂方法模式

  定义:工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

  可以看到工厂方法模式中定义了一个工厂接口,而具体的创建工作推迟到具体的工厂类,它是对简单工厂模式中的工厂类进一步抽象化,从而产生一个工厂类的抽象和实现体系,从而弥补简单工厂模式对修改开放的诟病。

  下面是百度百科中给出的该模式的类图。

  可以看到,上面右半部分是产品抽象和实现体系,左半部分是工厂抽象和实现体系,其中工厂体系依赖于产品体系,每一个工厂负责创造一种产品,这就省去了简单工厂中的elseif判断,又客户端决定实例化一个特定的工厂去创建相应的产品。

  下面我们将类图翻译成代码,首先是抽象产品接口。

public interface Light {public void turnOn();public void turnOff();}

  下面是具体的产品。

public class BuldLight implements Light{public void turnOn() {System.out.println("BuldLight On");    }public void turnOff() {System.out.println("BuldLight Off");    }}

public class TubeLight implements Light{public void turnOn() {System.out.println("TubeLight On");    }public void turnOff() {System.out.println("TubeLight Off");    }}

  下面是抽象的工厂接口。

public interface Creator {public Light createLight();
}

  下面是具体的工厂类。

public class BuldCreator implements Creator{public Light createLight() {return new BuldLight();}}

public class TubeCreator implements Creator{public Light createLight() {return new TubeLight();}}

  测试一下。

public class Client {public static void main(String[] args) {Creator creator = new BuldCreator();Light light = creator.createLight();light.turnOn();light.turnOff();creator = new TubeCreator();light = creator.createLight();light.turnOn();light.turnOff();}
}

  测试结果。

  可以看到,如果新增产品,只需要添加一个产品类,一个该产品的工厂类即可,不需要修改任何代码。LZ在看这个模式的时候看到别人给出的例子是JDBC API的设计,觉得非常贴切。LZ也把这个例子记录在这里。

  众所周知,为了统一各个数据库操作的标准,于是有了JDBC的API,它提供了一系列统一的,标准化的操作数据库的接口,我们平时操作数据库,依赖的就是这些抽象,而不是具体的数据库的实现,那sun公司是怎么做到的呢?用的就是工厂设计模式。

  JDBC是如何统一了数据库世界的呢?其实最主要的就是靠两个接口。第一个接口是Driver,我们大体看下源码。

package java.sql;import java.sql.DriverPropertyInfo;
import java.sql.SQLException;/*** The interface that every driver class must implement.*/
public interface Driver {Connection connect(String url, java.util.Properties info)throws SQLException;
}

  connect方法即创造一个数据库连接,也就是说,Driver对象就是工厂模式中的Creator接口,即工厂类的抽象。

  这个类除了connect方法以外,还有很多其他方法,篇幅原因,就不一一展开了,我们只关心核心方法,接口上有一句注释,翻译过来是这是一个任何驱动类都必须实现的接口。也就是说,sun公司明确规定,所有数据库厂商都必须实现这个接口来提供JDBC服务,即java数据库连接服务。

  第二个接口是connect方法的返回抽象Connection对象,我们看一下源码,仍然只关心核心方法就可以。

package java.sql;import java.sql.PreparedStatement;
import java.sql.SQLException;/*** <P>A connection (session) with a specific* database. SQL statements are executed and results are returned* within the context of a connection.* <P>*/
public interface Connection  extends Wrapper {Statement createStatement() throws SQLException;PreparedStatement prepareStatement(String sql) throws SQLException;}

  以上两个接口作为JDBC API的一部分,它们相当于告诉了数据库生产厂商两个要求。

第一,数据库厂商要提供一个数据库驱动类,它的作用可以是可以创造数据库连接,而这个数据库连接向上转型为我们JDBC的Connection。

       第二,数据库厂商要提供一个数据库连接的实现类,这个实现类可以执行具体数据库的各个操作,比如帮我们执行SQL,返回执行结果,关闭连接等等。

  LZ把类图画了一下,UML类图对设计模式这块非常重要,我个人的经验是,永远不要记代码,要记设计思想,记UML类图,记应用场景,所谓用抽象构建框架,用细节扩展实现

  多标准的工厂方法设计模式啊,sun公司正是用这个模式统一了数据库世界。工厂方法模式就是提供一个抽象的工厂,一个抽象的产品,在上述当中相当于Driver(数据库连接工厂)和Connection(抽象产品),实现的一方需要提供一个具体的工厂类(比如mysql驱动)和一个具体的产品(比如mysql数据库连接)。

  客户端调用时不依赖于具体工厂和产品(即到底是mysql驱动,mysql数据库连接还是oracle驱动,oracle连接,我们程序猿不需要管的,我们只管使用抽象的driver和connection,对吧?),而是依赖于抽象工厂和抽象产品完成工作。

  类图里还有个DriverMananger,DriverMananger在这个设计当中扮演者一个管理者的角色,它帮我们管理数据库驱动,让我们不需要直接接触驱动接口,我们获取连接只需要和DriverManager打交道就可以,也就是说客户端依赖于DriverManager和Connection就可以完成工作,不再需要与Driver关联,所以上述说我们依赖于Driver和Connection,现在DriverManager帮我们管理Driver,那我们只需要依赖于DriverManager和Connection就可以了。回想我们刚开始学习JDBC的时候,是不是只要让数据库厂商提供的具体数据库连接类加载,就可以直接从DriverManager里取连接了,所以这是sun公司为了方便编码给我们提供的一个管理类。

 三、抽象工厂模式

  抽象工厂模式算是工厂相关模式的终极形,基于上面的理解,我们不难理解抽象工厂模式,它与工厂方法唯一的区别就是工厂的接口里是一系列创造抽象产品的方法,而不再是一个,而相应的,抽象产品也不再是一个了,而是一系列相关的产品。这其实是工厂方法模式的一种扩展不是吗?

  定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

  我们看下百度百科给出的类图。

  我们把类图翻译成代码看一下。首先是产品族,也就是类图右边部分。

package net;interface ProductA {void methodA();
}interface ProductB {void methodB();
}class ProductA1 implements ProductA{public void methodA() {System.out.println("产品A系列中1型号产品的方法");}}class ProductA2 implements ProductA{public void methodA() {System.out.println("产品A系列中2型号产品的方法");}}class ProductB1 implements ProductB{public void methodB() {System.out.println("产品B系列中1型号产品的方法");}}class ProductB2 implements ProductB{public void methodB() {System.out.println("产品B系列中2型号产品的方法");}}

  左半部分。

package net;public interface Creator {ProductA createProductA();ProductB createProductB();}

package net;public class ConcreteCreator1 implements Creator{public ProductA createProductA() {return new ProductA1();}public ProductB createProductB() {return new ProductB1();}}
package net;public class ConcreteCreator2 implements Creator{public ProductA createProductA() {return new ProductA2();}public ProductB createProductB() {return new ProductB2();}}

  测试一下。

package net;public class Client {public static void main(String[] args) throws Exception {Creator creator = new ConcreteCreator1();ProductA productA = creator.createProductA();ProductB productB = creator.createProductB();productA.methodA();productB.methodB();creator = new ConcreteCreator2();productA = creator.createProductA();productB = creator.createProductB();productA.methodA();productB.methodB();}
}

  综上所述,简单工厂→工厂方法→抽象工厂,是一步步进化的过程。

  1,首先从简单工厂进化到工厂方法,是因为工厂方法弥补了简单工厂对修改开放的弊端,即简单工厂违背了开闭原则。

  2,从工厂方法进化到抽象工厂,是因为抽象工厂弥补了工厂方法只能创造一个的产品的弊端。

  工厂设计模式可能对像LZ这样平时只针对业务编码的程序猿来说用到的机会少一点,但是我们在看源码的过程中一定会看到这个模式,比如前面提到的JDBC,现在相信再回头看JDBC的源码,就能看懂当年sun公司为什么要这么去设计代码,大牛们牛X的地方,我们才能真的体会到。

转载于:https://www.cnblogs.com/peterxiao/p/10207598.html

设计模式(五)--工厂模式汇总相关推荐

  1. 系统架构技能之设计模式-抽象工厂模式

    一.上篇回顾 上篇我们主要讲述了简单工厂模式和工厂模式.并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下: 简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建 ...

  2. java 设计模式 路由器_java设计模式2————工厂模式

    java设计模式2----工厂模式 1.工厂模式介绍: 1.1.实现了创建者与调用者的分离 1.2.详细分类: 简单工厂模式 工厂方法模式 抽象工厂模式 1.3.所遵循的OOP原则: 开闭原则:对扩展 ...

  3. Java设计模式(工厂模式>抽象工厂模式和原型模式)

    Java设计模式Ⅱ 1.工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 2.抽象工厂模式 3.总结 4.原型模式 4.1 原型模式 4.2 浅拷贝 4.3 深拷贝 5.建造者模式 1.工厂模式 ...

  4. JavaScript设计模式--简单工厂模式例子---XHR工厂

    JavaScript设计模式--简单工厂模式例子---XHR工厂 第一步,Ajax操作接口(目的是起一个接口检测作用) (1)引入接口文件 //定义一个静态方法来实现接口与实现类的直接检验 //静态方 ...

  5. 三角形圆形创建与擦除java_设计模式---------------简单工厂模式

    设计模式---------------简单工厂模式 一.题目(Question) 使用简单工厂模式设计一个可以创建不同几何形状(如圆形.方形和三角形等)的绘图工具,每个几何图形都要有绘制draw()和 ...

  6. 策略模式和工厂模式的区别_设计模式之工厂模式-工厂方法模式

    设计模式之工厂模式-工厂方法模式 大家好,欢迎来到污污弹公司,今天司小司又接到了一个新活-披萨项目. 来源:凯哥Java(kaigejava) 需求: 披萨项目: 要方便披萨品种的扩展.要便于维护.要 ...

  7. Java 设计模式之工厂模式(二)

    原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...

  8. 设计模式之工厂模式(三)

    上一次我们已经通过代码,简单的认识了工厂方法模式,具体的思路请移步到设计模式之工厂模式(二),进行查看.这次,让我们通过设计模式的思想,来好好认识下工厂方法模式. 创建者和产品 所有工厂模式都用来封装 ...

  9. php工厂模式和单例模式,php 设计模式之工厂模式、单例模式、注册树模式

    php 设计模式之工厂模式.单例模式.注册树模式 在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问题,具体说是向设计中增加复 ...

  10. 教你如何一篇博客读懂设计模式之—--工厂模式

    一篇博客读懂设计模式之-工厂模式 工厂模式在我们日常开发的时候经常用到,相信大家都有了一定的了解,工厂模式是一种创建对象的设计模式,它提供一种创建对象的最佳方式. 主要过程是: 定义一个创建对象的接口 ...

最新文章

  1. java中的内省 (Introspector)
  2. Java继承Thread类创建多线程
  3. VTK:折线用法实战
  4. android StringBuffer实现换行
  5. 【转】关于LoadRunner的迭代
  6. 文本处理算法_python 文本处理
  7. 【Spring】HttpMessageConverter的作用及替换
  8. mysql pgsql 语法_PostgreSQL ALIAS语法
  9. 简述RPL, DPL, CPL的区别与联系
  10. C语言 一个字符串翻转函数的编写
  11. audio语音相关的基础知识-VAD,ASR,AEC,AGC,BF等
  12. 数字选择器NumberPicker使用教程
  13. 考研英语(四)——名词性从句
  14. Halcon错误 #2021: System clock has been set back.
  15. ps3本服务器维修,ps3端ftp服务器
  16. 5G前传从无源到半有源平滑演进解决方案
  17. 解开神经科学中的交叉频率耦合
  18. 使用stream流进行集合排序取最大值,根据集合中的bigdemal属性排序(正序反序)并取最大值
  19. 一年有50万主播入驻淘宝,宇宙的尽头是编制,直播的尽头是淘宝?
  20. Shader实现马赛克

热门文章

  1. Linux上静态库和动态库的编译和使用
  2. POJ--3974 Palindrome(回文串,hash)
  3. Unity优化之GC——合理优化Unity的GC (难度3 推荐5)
  4. (九十三)蓝牙的基本使用
  5. LaTeX 基础笔记。开篇
  6. /usr/bin/ld: cannot find -l*** 这里***可以指lapack等
  7. C语言结构体数组的使用
  8. Ubuntu中安装Eclipse的SVN插件——subclipse
  9. 推荐几个最近Star过的Github仓库
  10. 备份ad_IT管理公开课——备份恢复解决方案