文章目录

  • 六、工厂设计模式
    • 6.1 简单工厂设计模式
      • 6.1.1 设计需求
      • 6.1.2 使用接口改进代码
      • 6.1.3 使用简单工厂再改进
      • 6.1.4 简单工厂的优缺点
    • 6.2 工厂方法设计模式
      • 6.2.1 工厂方法的实现
      • 6.2.2 工厂方法的优缺点
    • 6.3 抽象工厂设计模式
      • 6.3.1 抽象工厂设计模式概述
        • 1)同族和同级
        • 2)同族的概念
      • 6.3.2 抽象工厂的实现
      • 6.3.3 抽象工厂的优缺点

六、工厂设计模式

工厂设计模式,顾名思义,就是用来生产对象的,在Java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则(一个好的软件实体应该对扩展开放,对修改关闭);另外,如果创建一个类的过程过于复杂,如需要传递过多的构造方法参数等,那么创建对象将会变得非常麻烦,并且会与其他业务类进行耦合。当这个类发生修改时,就需要在任何引用该类的源代码处进行修改;后期维护成本将会变得巨大;

如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;

工厂设计模式分为三种,分别为简单工厂设计模式、工厂方法设计模式、抽象工厂设计模式;

6.1 简单工厂设计模式

简单工厂模式(Simple Factory):简单工厂模式又称为静态工厂方法模型,它属于类创建型模式。在简单工厂模式中,可以根据方法的参数不同返回不同类的实例。简单工厂专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

Tips:简单工厂设计模式不在GoF23种设计模式之中;

6.1.1 设计需求

  • 设计一个计算类,具备基本的加减乘除方法:
package com.dfbz.demo01_简单工厂设计模式.demo01_需求;/*** @author lscl* @version 1.0* @intro:*/
public class Operation {/*** 计算方法* @param num1* @param num2* @param operate* @return*/public static Double getResult(double num1, double num2, String operate) {Double result = 0.0D;switch (operate) {case "+":result = num1 + num2;break;case "-":result = num1 - num2;break;case "*":result = num1 * num2;break;case "/":result = num1 / num2;break;}return result;}
}
  • 测试类:
package com.dfbz.demo01_简单工厂设计模式.demo01_需求;import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_测试加减乘除计算类 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入第一个数: ");double num1 = scanner.nextDouble();System.out.println("请输入第一个数: ");double num2 = scanner.nextDouble();System.out.println("请输入您要执行的运算符(+、-、*、/): ");String operate = scanner.next();Double result = Operation.getResult(num1, num2, operate);System.out.println("运算的结果: " + result);}
}

6.1.2 使用接口改进代码

在上述案例程序中,代码耦合性太高,假设程序需要改进加法算法,则必须把所有的代码全部提供;并且由于所有的算法都在一起,试想一下假设一个加法算法的代码在几千行,那么程序将变得难以维护,不利于各个部件的单独升级,我们要做的是将各个部件独立出来;这样方便以后的升级扩展,并且各个模块相对独立;

  • 设计计算类的顶层接口:
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;/*** @author lscl* @version 1.0* @intro:*/
public interface Operation {/*** 负责计算两个两个数的运算结果集,到底做什么运算,交给子类* @param num1* @param num2* @return*/public Double getResult(Double num1,Double num2);
}
  • 加法类:
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;/*** @author lscl* @version 1.0* @intro:*/
public class OperationAdd implements Operation{@Overridepublic Double getResult(Double num1, Double num2) {return num1 + num2;}
}
  • 减法类:
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;/*** @author lscl* @version 1.0* @intro:*/
public class OperationSub implements Operation {@Overridepublic Double getResult(Double num1, Double num2) {return num1 - num2;}
}
  • 测试代码:
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入第一个数: ");double num1 = scanner.nextDouble();System.out.println("请输入第一个数: ");double num2 = scanner.nextDouble();System.out.println("请输入您要执行的运算符(+、-、*、/): ");String operate = scanner.next();Operation operation = null;switch (operate) {case "+":operation = new OperationAdd();break;case "-":operation = new OperationSub();}Double result = operation.getResult(num1, num2);System.out.println("计算的结果集为: " + result);}
}

6.1.3 使用简单工厂再改进

使用接口改进后的代码各个部件相对独立,如果以后需要修改加法类的算法也不用提供其他算法类的具体实现;但是上述代码中还存在一个具体的问题,那就是如果以后新增了其他的算法,源代码则需要一直改变;这样违反了开闭原则,我们的程序应该是"对扩展开放,对修改关闭";即类可以新增,但源代码尽量不要再修改;

  • 设计一个工厂类:
package com.dfbz.demo01_简单工厂设计模式.demo03_使用简单工厂再改进;/*** @author lscl* @version 1.0* @intro:*/
public class OperationFactory {/*** 根据计算方式来选择创建对应的对象** @param method* @return*/public static Operation createOperation(String method) {Operation operation = null;if (method.equals("+")) {operation = new OperationAdd();} else if (method.equals("-")) {operation = new OperationSub();}return operation;}}
  • 测试类:
package com.dfbz.demo01_简单工厂设计模式.demo03_使用简单工厂再改进;import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入第一个数: ");double num1 = scanner.nextDouble();System.out.println("请输入第一个数: ");double num2 = scanner.nextDouble();System.out.println("请输入您要执行的运算符(+、-、*、/): ");String method = scanner.next();Operation operation = OperationFactory.createOperation(method);Double result = operation.getResult(num1, num2);System.out.println("计算的结果集为: " + result);}
}

就这样,一个简单工厂设计模式就完成了。在简单工厂模式下,任何的运算逻辑新增或者修改,都不会影响客户端的代码(Demo01),只需要添加Operation的实现类,并且修改工厂类添加逻辑即可;降低了程序的耦合性;

但是,简单工厂只做到了一半的"开闭原则",因为在简单工厂中,新增了新的算法类,需要修改工厂类;如果我们需要频繁的新增一些算法则会导致频繁修改工厂类;简单工厂中,不仅对扩展开放了,对修改也开放了;

Tips:简单工厂只适合于产品对象较少,且产品固定的需求,对于产品变化无常的需求来说显然不合适;

6.1.4 简单工厂的优缺点

  • 优点:

    • 封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
  • 缺点:
    • 1)增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
    • 2)简单工厂模式的工厂类单一,负责所有产品的创建,但产品基数增多时,工厂类将会变得非常臃肿,违背高内聚低耦合原则;

6.2 工厂方法设计模式

工厂设计模式(Factory Method):指定一个创建对象的接口,由接口的实现类来决定实例化哪个类,工厂方法把类的实例化工作延迟到子类中进行;

在简单工厂中,随着产品链的丰富,则工厂的职责会变得越来越多,这样并不利于维护。工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

6.2.1 工厂方法的实现

工厂方法中,不仅把产品抽象出来,连工厂类也抽象出来,具体生成什么产品由子类来决定;

  • 改进后的类图如下:

在工厂方法中,如果要对算法进行扩展,那么就新增一个工厂并且再新增一个具体算法类即可,工厂方法完全符合了开闭原则的对扩展开发,对修改关闭的原则;

  • 工厂抽象接口:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public interface IFactory {Operation createOperation();
}
  • 产品抽象接口:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public interface Operation {/*** 负责计算两个两个数的运算结果集,到底做什么运算,交给子类* @param num1* @param num2* @return*/public Double getResult(Double num1,Double num2);
}
  • 专门用于生成加法产品的工厂类:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class OperationAddFactory implements IFactory{@Overridepublic Operation createOperation() {return new OperationAdd();}
}
  • 专门用于生成减法产品的工厂类:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class OperationSubFactory implements IFactory{@Overridepublic Operation createOperation() {return new OperationSub();}
}
  • 加法产品:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class OperationAdd implements Operation {@Overridepublic Double getResult(Double num1, Double num2) {return num1 + num2;}
}
  • 减法产品:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class OperationSub implements Operation {@Overridepublic Double getResult(Double num1, Double num2) {return num1 - num2;}
}
  • 测试类:
package com.dfbz.demo02_工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01 {public static void main(String[] args) {// 创建工厂IFactory factory=new OperationAddFactory();// 创建运算类Operation operation = factory.createOperation();// 做运算Double result = operation.getResult(20.0D, 30.0D);}
}

工厂方法完完全全做到了开闭原则,以后我们要新增一些算法,或者第三方厂商想要新增一些算法,那么直接进行子类扩展就行;

6.2.2 工厂方法的优缺点

  • 优点:

    • 1)职责相对于简单工厂来说,更加明确。不仅将产品类独立,还将产品工厂独立,以后修改产品工厂内部逻辑变得清晰明了;
    • 2)在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
    • 3)高层模块只需要知道产品的抽象类,无须关系其他实现类,符合迪米特法则,依赖倒转原则;
  • 缺点:
    • 1)每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,类的数量增多,这增加了系统的复杂度。
    • 2)每个工厂只能生产一种产品,该问题可以使用抽象工厂来解决。

6.3 抽象工厂设计模式

6.3.1 抽象工厂设计模式概述

在工厂方法设计模式中,工厂生产的是总是同一类的产品;例如产品1工厂只能生产产品1,产品2工厂只能生产产品2;这些工厂只生产同种类产品而抽象工厂模式将考虑多种类产品的生产。在抽象工厂中,将同一种工厂生产出来的产品称为同族产品,而同一种工厂生产出来的不同产品称为同级产品;

例如电子设备工厂能够生产手机,笔记本;旗下有小米工厂,华为工厂;小米工厂能够生产小米手机,小米笔记本;华为工厂能够生产华为手机,华为笔记本;

程序类图如下:

  • 同族产品:

    • 小米手机,小米笔记本属于同族产品,都属于小米品牌(都属于小米工厂创建的产品)
    • 华为手机,华为笔记本属于同族产品,都属于华为品牌(都属于华为工厂创建的产品)
  • 同级产品:
    • 小米手机,华为手机属于同级产品,都属于手机产品
    • 小米笔记本,华为笔记本属于同级产品,都属于笔记本产品

1)同族和同级

同族:只要是同一个工厂生产的产品都属于同族产品

  • 小米,小米手机,小米笔记本,小米智能机,小米老年机,小米游戏本,小米商务本等都属于小米工厂生产的产品,属于同族;

同级:工厂生产出来的产品的类别称为级别,所属同一个类别的产品,那么就是同级别产品;

  • 小米手机,华为手机都是属于手机,属于同级产品;
  • 小米笔记本,华为笔记本都是属于笔记本,属于同级产品;

2)同族的概念

同族是有相对概念的问题,主要看我们的程序是如何设计的

  • 关于同族:只要是同一个工厂生产的产品都属于同族产品;

  • 关于同级:工厂生产出来的产品的类别称为级别,所属同一个类别的产品,那么就是同级别产品;

例如,在下面类图中,同族与同级的关系发生了变化:

同族产品:

  • 小米智能机,华为智能机属于同族产品,都属于老年机厂商生产的产品
  • 小米老年机,华为老年机属于同族产品,都属于智能机厂商生产的产品

同级产品:

  • 小米智能机,小米老年机属于同级产品;都属于小米类别
  • 华为智能机,华为老年机属于同级产品;都属于华为类别

6.3.2 抽象工厂的实现

抽象工厂模式的主要角色如下。

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
  2. 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

基于类图设计程序:

抽象工厂:

package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro: 电子设备工厂, 用于生产电子设备*/
public abstract class AbstractFactory {// 生产手机public abstract Phone createPhone();// 生产笔记本public abstract Laptop createLaptop();
}
  • 具体工厂1-小米工厂:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro: 小米工厂,用于生产小米的设备*/
public class XiaoMiFactory extends AbstractFactory{@Overridepublic Phone createPhone() {return new XiaoMiPhone();}@Overridepublic Laptop createLaptop() {return new XiaoMiLaptop();}
}
  • 具体工厂2-华为工厂:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro: 华为工厂,用于生产华为的设备*/
public class HuaWeiFactory extends AbstractFactory {@Overridepublic Phone createPhone() {return new HuaWeiPhone();}@Overridepublic Laptop createLaptop() {return new HuaWeiLaptop();}
}
  • 抽象产品1-手机:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro: 抽象产品,抽象手机,每个手机的功能是不一样的,具体的实现交给子类*/
public abstract class Phone {public abstract void sendMsg();
}
  • 抽象产品2-笔记本:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro: 抽象产品,抽象笔记本,每个笔记本的功能是不一样的,具体的实现交给子类*/
public abstract class Laptop {public abstract void play();
}
  • 具体产品1-小米手机:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class XiaoMiPhone extends Phone {@Overridepublic void sendMsg() {System.out.println("使用小米手机发送短信....");}
}
  • 具体产品2-小米笔记本:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class XiaoMiLaptop extends Laptop {@Overridepublic void play() {System.out.println("使用小米笔记本打游戏...");}
}
  • 具体产品3-华为手机:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class HuaWeiPhone extends Phone {@Overridepublic void sendMsg() {System.out.println("使用华为手机发送短信....");}
}
  • 具体产品4-华为笔记本:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class HuaWeiLaptop extends Laptop {@Overridepublic void play() {System.out.println("使用华为笔记本打游戏...");}
}
  • 测试类:
package com.dfbz.demo03_抽象工厂设计模式;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01 {public static void main(String[] args) {// 使用华为工厂来创建电子设备AbstractFactory factory=new HuaWeiFactory();Laptop laptop = factory.createLaptop();Phone phone = factory.createPhone();laptop.play();phone.sendMsg();System.out.println("----------");// 使用小米工厂来创建电子设备AbstractFactory factory2=new XiaoMiFactory();Laptop laptop2 = factory.createLaptop();Phone phone2 = factory.createPhone();laptop2.play();phone2.sendMsg();}
}

6.3.3 抽象工厂的优缺点

  • 优点:

    • 1)类的继承体系结构清晰明确,对类的管理方便
    • 2)有了抽象工厂,当新增一个产品族时,不需要修改源代码,例如还要新增一个联想产品族,只需要自己编写联想工厂,联想手机,联想笔记本等即可,程序的扩展性强,符合开闭原则;
    • 3)当一个产品线中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品线中的对象。
  • 缺点:

    • 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。例如抽象工厂不仅要生产手机和笔记本要生产电视机,那么所有的工厂包括小米工厂,华为工厂等都行呀新增对生产电视机这种产品的实现;

06【工厂设计模式】相关推荐

  1. 设计模式 工厂方法_工厂设计模式–一种有效的方法

    设计模式 工厂方法 如您所知,"工厂方法模式"或俗称"工厂设计模式"是"创意设计模式"类别下的一种设计模式. 模式背后的基本原理是,在运行时 ...

  2. 工厂设计模式和策略设计模式_设计模式:策略

    工厂设计模式和策略设计模式 这次我想谈谈策略设计模式 . 通过这种方式,我开始撰写有关行为设计模式的文章. 这种模式表示对象之间的某些交互模式,以使代码更灵活且组织得更好.此方法的最本质点是对象之间的 ...

  3. 工厂设计模式–一种有效的方法

    如您所知,工厂方法模式或俗称工厂设计模式是"创意设计模式"类别下的一种设计模式. 模式背后的基本原理是,在运行时,我们根据传递的参数获得类似类型的对象. 关于这种模式有很多文章,开 ...

  4. 设计模式之二抽象工厂设计模式

    继上篇简单工厂设计模式之后,今天继续讲解抽象工厂设计模式.在简单工厂中,我们的工厂类一次只可以处理一类产品.那么如果我们想处理多类产品,简单工厂是满足不了的.必须要用抽象工厂设计模式. 我们先从概念上 ...

  5. php使用接口实现工厂设计模式

    php实现工厂设计模式,使用接口实现,表面上接口没有什么用,因为php是类型自动转换的.实现上使用接口可以约束类的定义,从而实现一致的访问. 接口在php只能起到约束类的定义作用,虽不像c#/java ...

  6. Java设计模式(四):工厂设计模式

    1. 工厂设计模式 1.1 应用场景 由于需求的变化,一个类的子类经常面临着剧烈的变化,但他却拥有比较稳定的接口.使用一种封装机制来"隔离这种易变对象的变化",工厂方法定义一个用于 ...

  7. 工厂设计模式----python版本

    #!/usr/bin/python # -*- coding: UTF-8 -*- #工厂设计模式 ''' date:2016/8/21 ''' #形状接口 class Shape(object):d ...

  8. 用C# (.NET Core) 实现抽象工厂设计模式

    本文的概念性内容来自深入浅出设计模式一书.上一篇文章讲了简单工厂和工厂方法设计模式 使用的是披萨店的例子. 文将继续使用这个例子, 这里要用到抽象工厂. 披萨店的需求变更 现在披萨店在各地授权了很多连 ...

  9. 抽象工厂和工厂方法示例_抽象工厂设计模式示例

    抽象工厂和工厂方法示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此 ...

最新文章

  1. 通用数据库连接执行类(SQL)
  2. object+java+equals_java-为什么SparseIntArray.equals(Object)不起作用?
  3. mysql数据库引擎博客_mysql 数据库引擎常识全集
  4. Linux vi/vim基础知识
  5. linux虚拟机dhcp启动失败,Linux 的dhcp启动异常之No subnet declaration for eth1 (192.168.48.134)...
  6. 20个linux命令行工具监视性能(上)
  7. Flume-NG + HDFS + HIVE 日志收集分析 | EyeLu技术Blog
  8. 蓝桥杯大赛青少年创意编程C++ 资料集
  9. URAL 1664 Pipeline Transportation
  10. java table 内容居中_JTable内容居中显示 | 学步园
  11. Flink SQL 在快手的扩展和实践
  12. 运维工具之轻量级自动化运维工具Fabric源码安装
  13. 康熙字典收录多少汉字_《康熙字典》一共有多少个字
  14. 前端图片文字复制粘贴功能
  15. 泛函分析 04.02 有界线性算子 - 有界线性算子空间的收敛与完备性
  16. JavaScript的回调函数及Ajax中的回调函数
  17. redis集群报错(error) CLUSTERDOWN Hash slot not served
  18. 私有化部署文字识别SDK
  19. 在树莓派上安装Ubuntu
  20. 关于两个数相乘, 求其为多少进制

热门文章

  1. 白龙马科技大数据面试题
  2. linux namespace简单操作
  3. 机器翻译:引入注意力机制的Encoder-Decoder深度神经网络训练实战中英文互译(完结篇)
  4. 2018-10-28-chicken-soup
  5. 前端面试问题总结(二)7.5
  6. Android系统10 RK3399 init进程启动(三十六) 属性property操作API
  7. 2023年信息与通信工程国际会议(JCICE 2023)
  8. 怎么获取商品sku信息api接口
  9. unity,大鱼吃小鱼
  10. Windows远控之权限维持