博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式<四>简单工厂模式与工厂方法模式
阅读量:2401 次
发布时间:2019-05-10

本文共 4954 字,大约阅读时间需要 16 分钟。

设计模式概述见:

简单工厂模式的基本概念

简单工厂模式是一种创建型模式,它根据外界给定的信息生成外界需要的对象。

它不属于23种GOF设计模式之一。
和我们所理解的工厂一样,简单工厂模式直接生产对象。
随手画了一个很不规范的简单的实现图,就体现个思想。
产品可以是接口也可以是抽象类,我们通过一个工厂封装了生成产品的逻辑。

什么时候使用简单工厂模式

工厂模式的运用在解耦上,例如当实例化一个对象A a=new A()时,

如果在很多的地方使用了N个A a = new A();如果某一天,这个A类需要发生一些变化,或者简单说,A的初始化方式从new A();变成了new A(1);那么我们就会需要将所有用到A a = new A();的地方全部改成A a=new A(1);。
如果在这之前,我们已经将他封装进了工厂,通过工厂来获取,那么我们只需要改变工厂,客户对对象的调用依旧是通过给工厂的参数来获取。

又比方说客户需要一个加法就需要通过Add add = new Add();而工厂模式只需要让客户知道”+”即可,生成具体加法对象的细节都被封装进了工厂,这就是解耦了。

简单工厂模式运用在工厂负责创建的类比较少的情况下,因为当类多了,类的复杂程度高了,反而违背了使用设计模式的初衷。

它通常用在当一个类的创建逻辑比较复杂时,而客户端又仅仅想要得到最后的对象,并不想知道它是怎么得到的,在需要创建的类比较少且变动一般比较少的时候,我们会使用简单工厂模式。

简单工厂模式怎么用

以下举最通俗的加减乘除来解释。

简单工厂模式是通过客户端给的信息生产出相应的对象,所以需要有一个基类或是接口来承载这些对象。
我们从加减乘除中提取出公有的算法接口,所有算法都有这样的一个方法:getResult();
提取出算法接口:

/*** @ClassName: calc * @Description: 算法接口 * @author cjd* @date 2017年12月19日 上午9:59:44   */public interface Calc {
int getResult(int a,int b);}

一个加法实体类,一个减法实体类

/*** @ClassName: Add * @Description: 加法类 * @author cjd* @date 2017年12月19日 上午10:03:56   */public class Add implements Calc {
@Override public int getResult(int a, int b) { return a+b; }}
/*** @ClassName: Reduce * @Description: 减法类 * @author cjd* @date 2017年12月19日 上午10:04:11   */public class Reduce implements Calc {
@Override public int getResult(int a, int b) { return a-b; }}

以及一个生产算法的工厂:

/*** @ClassName: CalcFactory * @Description: 算法工厂* @author cjd* @date 2017年12月19日 上午10:07:06   */public class CalcFactory {
public static Calc createCalc(String type) { Calc calc = null; switch (type) { case "+": calc = new Add(); break; case "-": calc = new Reduce(); break; } return calc; }}

简单工厂模式就是根据客户提供的信息生产出客户需要的对象。

所以,我们在主函数上的调用为

/*** @ClassName: Main * @Description: TODO(这里用一句话描述这个类的作用) * @author cjd* @date 2017年12月19日 上午10:06:37   */public class Main {
public static void main(String[] args) { Calc calc=CalcFactory.createCalc("+"); int resultAdd=calc.getResult(1,2); Calc calc=CalcFactory.createCalc("-"); int resultReduce=calc.getResult(1,2); System.out.println(resultAdd+" "+resultReduce); }}

客户通过给静态工厂一个’+’,静态工厂通过内部方法返回new Add()对象,当我们需要修改加法算法时,只需要找到加法类完成修改,所有调用到的地方都会随之修改,同时,如果需要添加什么新的算法,也避免了可能会发生的对其余算法造成的影响。

例子仅以表示简单工厂模式的简单运用方式。
如果让我用一句话来描述:简单工厂模式直接生产对象。

工厂方法模式的基本概念

工厂方法模式是一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。

它是简单工厂的衍生,简单工厂的工厂类直接负责创建多个对象。工厂类的核心工厂不能生成对象是一个抽象工厂,具体工厂继承了核心工厂生产单一类。
简单说,一个工厂生产一个产品。工厂由抽象工厂而来,产品由抽象产品而来。
这里写图片描述
图只是表示一个思想,可以和简单工厂进行一个对比。

什么时候使用工厂方法模式

工厂方法模式主要是解决了简单工厂的种种弊端,弊端我在文章末已经记下来了。

所以,当类的变换比较多,逻辑比较复杂,需要经常进行添加修改之类的时候,简单工厂的设计就不能满足了,通过工厂模式可以解决这些弊端。
以上面的图论,简单工厂模式是一个工厂生产N个对象,设计简单,但是类多了逻辑复杂了就不适用了,工厂方法模式是一个工厂生产单一对象,但是每增加一个类就要多增加一个工厂类,类的开销大了。都是一个个有利有弊的模式。

工厂方法模式怎么用

工厂方法模式通过一个工厂对应一个类的方法来创建对象。

它有一个抽象工厂,多个具体工厂(继承抽象工厂),一个抽象产品,一个具体产品(继承抽象产品)。
原本通过new直接创建具体产品,现在增加了一个抽象工厂和抽象产品来实现具体产品和具体工厂的关联。每当我们需要一个新的产品,就需要先创建一个具体工厂继承抽象工厂,再由具体工厂生产具体产品。

如果不理解,就看这样几句话:

抽象工厂生产抽象产品是一个格式。
具体类继承了抽象工厂,具体产品继承了抽象产品。
因为抽象工厂生产抽象产品,所以具体类生产具体产品。

工厂方法模式就是把实例化对象的过程封装到工厂中,但是为了避免简单工厂的高聚合性,也为了满足开闭原则的要求,所以通过工厂→产品一对一的关系来生产。

首先,我们需要创建一个抽象共享以及一个抽象产品,可以是接口也可以是抽象类。

/*** @ClassName: CalcFactory * @Description: 抽象工厂,或者叫核心工厂* @author cjd* @date 2017年12月19日 上午10:07:06   */public interface CalcFactory {
Calc createCalc();}
/*** @ClassName: calc * @Description: 抽象产品* @author cjd* @date 2017年12月19日 上午9:59:44   */public interface Calc {
void calc(int a,int b);}

具体实现就时每当创建一个类,就需要创建它的工厂类,这里我们需要一个加法类和减法类,所以我们也需要加法工厂和减法工厂。

具体工厂类:

class AddFactory implements CalcFactory {
@Override public Calc createCalc() { return new Add(); }}class ReduceFactory implements CalcFactory {
@Override public Calc createCalc() { return new Reduce(); }}

具体产品类:

class Add implements Calc {
@Override public void calc(int a, int b) { System.out.println(a + b); }}class Reduce implements Calc {
@Override public void calc(int a, int b) { System.out.println(a - b); }}

客户端进行调用如下:

/*** @ClassName: Main * @Description: 主函数* @author cjd* @date 2017年12月20日 上午11:27:04   */public class Main {
public static void main(String[] args) { AddFactory addFactory = new AddFactory(); Calc add=addFactory.createCalc(); add.calc(2,5); ReduceFactory reduceFactory = new ReduceFactory(); Calc reduce=reduceFactory.createCalc(); reduce.calc(5,2); }}

通过具体工厂创建具体类,使用工厂方法的好处也一览无余,

每当我们需要增加一个新的产品,不用修改核心工厂的代码,这也符合了开闭原则和单一原则的设计。

后记

简单工厂模式有这样的几个缺点:

  • 因为单一的工厂类集中了所有实例的创建规则,所以如果这个工厂类出现了问题,会导致内部整个系统出现问题。
  • 它违反了设计模式的开闭原则,因为每当我们需要添加新的类,就需要修改工厂模式。逻辑会越来越复杂,可以通过反射机制避免这一缺点。
  • 一般简单工厂模式又叫做静态工厂模式,因为静态,所以它不能被继承重写。
    以上为简单工厂模式的几个局限点,简单工厂是工厂方法模式的一个退化版本,工厂方法模式也解决了以上的几个问题,简单工厂适用于简单的变化之中。

工厂方法模式为了解决以上的一些缺点而产生,有利有弊,每当我们需要创建一个新的类,我们就需要创建它的工厂类,再通过工厂类返回具体类,导致在类的开销上会成倍增加。

一开始学习设计模式可能会有这样的困惑:为什么直接new A()中间非要加一个创建工厂的步骤来关联,这个疑问我也有,可当我一个个设计模式学下来,再回去看设计模式的几个原则,懂了自然就懂了。

若有理解错误,感谢指出!

你可能感兴趣的文章
Java Servlet和JSP教程(10)(转)
查看>>
怎样制作恢复光盘(转)
查看>>
广州一银行偷逃个税300万职员人均补税近万元
查看>>
山西晋中6辆警车围堵太原许西收费站
查看>>
Linux下的压缩文件剖析(转)
查看>>
基础网络命令(转)
查看>>
广域网(WAN)简介(转)
查看>>
DDN综述-1(转)
查看>>
详细定义嵌入式系统(转)
查看>>
linux入门教程(3)(转)
查看>>
动手制作自己的启动盘(转)
查看>>
在Linux中做系统引导盘(转)
查看>>
2.6内核的安装(转)
查看>>
多用户,多语言设置(转)
查看>>
断电后的系统修复(转)
查看>>
Squid优化完全手册(1)(转)
查看>>
全都是外国人写的防火墙脚本,我也来写一个,希望大家跟我一块做好(转)
查看>>
使用iptables实现数据包过滤(转)
查看>>
创建iptables NAT规则(转)
查看>>
初始化简单的IP放火墙(Script)(转)
查看>>