设计模式(五)--工厂模式汇总

  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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何估算内存消耗?

这个故事可以追溯到至少十年之前&#xff0c;当时我第一次接触PHB时遇到一个问题&#xff1a;“在生产部署中&#xff0c;我们需要购买多大服务器”。 我们正在构建的新的&#xff0c;闪亮的系统距离生产开始还有9个月的时间&#xff0c;显然该公司已承诺提供包括硬件在内的整个…

python爬取b站403_Python如何爬取b站热门视频并导入Excel

代码如下 #encoding:utf-8 import requests from lxml import etree import xlwt import os # 爬取b站热门视频信息 def spider(): video_list [] url "https://www.bilibili.com/ranking?spm_id_from333.851.b_7072696d61727950616765546162.3" html requests.g…

使用调试器进行事后跟踪

我最近一直在使用的大多数调试器的好功能是能够在断点上记录信息。 这对理解代码而无需修改是非常有用的&#xff0c;它涉及字节码修改。 让我们考虑一下这种非常琐碎且效率低下的函数实现&#xff0c;以返回斐波那契数列中的第n个数字。 public class Fib {public long fib(…

链表排序c++代码_[链表面试算法](一) 链表的删除-相关题型总结(6题)

在数据结构的最高层抽象里&#xff0c;只有两种结构&#xff0c;数组和链表。这两种结构&#xff0c;是所有其他数据结构实现的基础。队列和栈&#xff0c;可以用链表和数组来实现。图&#xff0c;可以用邻接表和邻接矩阵来实现&#xff0c;其中&#xff0c;邻接表就是链表&…

c语言如何空格键返回主菜单,C语言中scanf函数与空格回车的用法说明

众所周知&#xff0c;C语言中的scanf函数的作用是从标准输入设备(通常是键盘)读取输入值&#xff0c;并存储到参数列表中指针所指向的内存单元。下面从几个方面说一下一些稍微细节的东西。下面的实验都在vc6.0中通过。1、scanf的返回值scanf通常返回的是成功赋值(从标准输入设备…

Linear_algebra_03_矩阵

1. 矩阵的线性运算&#xff1a; 2.1 矩阵的乘法&#xff1a;Xik * Ykj Zij 2.2 矩阵乘法性质&#xff1a; 3.1 矩阵的幂次方运算 3.2 矩阵转置的运算律 3.3 方阵运算 4 分块矩阵的运算 5. 矩阵的初等变换 5.1 单位矩阵I经过一次初等变换所得到的矩阵称为初等矩阵. 5.2 初等矩…

js转json工具_菜鸟丨Egert3D微信小游戏发布与Unity工具使用

本次教程将会为大家介绍Egret3D工具导出Unity场景对象的使用&#xff0c;以及发布微信小游戏流程。让大家对Egret 3D有更加熟悉的了解。需求工具&#xff1a;1、Unity场景导出插件&#xff1b;2、微信开发者工具。导出插件的使用一、打开需要导出的Unity场景&#xff0c;并且把…

OI杂记

从今天开始记录一下为数不多天的OI历程 8.25 上 今天举行了难得的五校联考&#xff0c;模拟noip&#xff0c;题目的解压密码竟然是$aKnoIp2o18$&#xff0c;对你没有看错&#xff01;&#xff01;&#xff01; 7:50老师&#xff1f;啊啊啊啊&#xff0c;收不到题目啊&#xff0…

Java,Steam控制器和我

您是否想过是否可以将现有的东西用于新的东西&#xff1f; 我看了一些所谓的“蒸汽控制器”&#xff08;从现在开始为SC&#xff09;的镜头&#xff0c;并看着我的游戏手柄。 问我自己是否有可能以类似蒸汽的方式使用它&#xff0c;我找到了一些Java库并创建了一个项目&#xf…

unknown column in field list_tf.feature_column的特征处理探究

1. 背景tf.estimator是tensorflow的一个高级API接口&#xff0c;它最大的特点在于兼容分布式和单机两种场景&#xff0c;工程师可以在同一套代码结构下即实现单机训练也可以实现分布式训练&#xff0c;正是因为这样的特点&#xff0c;目前包括阿里在内的很多公司都在使用这一接…

pytorch如何定义损失函数_对比PyTorch和TensorFlow的自动差异和动态模型

使用自定义模型类从头开始训练线性回归&#xff0c;比较PyTorch 1.x和TensorFlow 2.x之间的自动差异和动态模型子类化方法&#xff0c;这篇简短的文章重点介绍如何在PyTorch 1.x和TensorFlow 2.x中分别使用带有模块/模型API的动态子类化模型&#xff0c;以及这些框架在训练循环…

Gradle命令行便利

在我的《用Gradle构建Java的gradle tasks 》一文中&#xff0c;我简要地提到了使用Gradle的“ gradle tasks ”命令来查看特定Gradle构建的可用任务。 在这篇文章中&#xff0c;我将对这一简短提及进行更多的扩展&#xff0c;并查看一些相关的Gradle命令行便利。 Gradle可以轻松…

java封装实现Excel建表读写操作

对 Excel 进行读写操作是生产环境下常见的业务&#xff0c;网上搜索的实现方式都是基于POI和JXL第三方框架&#xff0c;但都不是很全面。小编由于这两天刚好需要用到&#xff0c;于是就参考手写了一个封装操作工具&#xff0c;基本涵盖了Excel表&#xff08;分有表头和无表头&a…

argmax函数_1.4 TensorFlow2.1常用函数

1.4 TF常用函数tf.cast(tensor,dtypedatatype)可以进行强制类型转换。tf.reduce_min(tensor)和tf.reduce_max(tensor)将计算出张量中所有元素的最大值和最小值。import tensorflow as tfx1 tf.constant([1., 2., 3.], dtypetf.float64)print("x1:", x1)x2 tf.cast(…

设计模式---数据结构模式之迭代器模式(Iterate)

一&#xff1a;概念 迭代模式是行为模式之一&#xff0c;它把对容器中包含的内部对象的访问委让给外部类&#xff0c;使用Iterator&#xff08;遍历&#xff09;按顺序进行遍历访问的设计模式。 在应用Iterator模式之前&#xff0c;首先应该明白Iterator模式用来解决什么问题。…

识别Gradle约定

通过约定进行配置具有许多优点&#xff0c;尤其是在简洁方面&#xff0c;因为开发人员不需要显式配置通过约定隐式配置的内容。 但是&#xff0c;在利用约定进行配置时&#xff0c;需要了解约定。 这些约定可能已经记录在案&#xff0c;但是当我可以编程方式确定约定时&#xf…

高校c语言题库,C语言-中国大学mooc-题库零氪

第1 周 程序设计与C语言简介1.1 程序设计基础随堂测验1、计算机只能处理由人们编写的、解决某些问题的、事先存储在计算机存储器中的二进制指令序列。第1周单元测验1、通常把高级语言源程序翻译成目标程序的程序称为( )。A、编辑程序B、解释程序C、汇编程序D、编译程序2、一个算…

场景法设计测试用例

在面向对象的软件开发中&#xff0c;事件触发机制是编程中经常遇到的。 &#xff08;一&#xff09;场景法原理 现在的软件几乎都是用事件触发来控制流程的。像GUI软件、游戏等。事件触发时的情景形成了场景&#xff0c;而同一事件不同的触发顺序和处理结果就形成了事件流。这种…

python中range函数是什么意思_python里range是什么

python range() 函数可创建一个整数列表&#xff0c;一般用在 for 循环中。函数语法&#xff08;推荐学习&#xff1a;Python视频教程&#xff09;range(start, stop[, step]) 参数说明&#xff1a; start: 计数从 start 开始。默认是从 0 开始。例如range&#xff08;5&#x…

android高德地图搜索地址,地点/周边搜索-Android平台-开发指南-高德地图车机版 | 高德地图API...

关键字搜索第三方通过该接口可传入关键字信息给auto&#xff0c;调起auto执行关键字搜索并跳转到搜索结果展现界面&#xff0c;官网版本都可支持参数说明参数说明是否必填类型ActionAUTONAVI_STANDARD_BROADCAST_RECV是stringKEY_TYPE协议ID:10036是intSOURCE_APP第三方应用名称…