【设计模式】工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)详记

注:本文仅供学习参考,如有错漏还请指正!

参考文献/文章地址:

  • https://zh.wikipedia.org/wiki/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%EF%BC%9A%E5%8F%AF%E5%A4%8D%E7%94%A8%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%BD%AF%E4%BB%B6%E7%9A%84%E5%9F%BA%E7%A1%80

  • https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/simple_factory.html

  • https://refactoringguru.cn/design-patterns/abstract-factory

文章目录

      • 一、关于GoF
        • 23种设计模式及其分类
          • 创建范例
          • 结构范例
          • 行为范例
      • 二、简单工厂模式(工厂方法的特殊形式)
        • 2.1 模式定义
        • 2.2 模式结构
        • 2.3 类图
        • 2.4 具体实现
        • 2.5 简单工厂模式的优缺点
      • 三、工厂方法模式
        • 3.1 模式定义
        • 3.2 模式结构
        • 3.3 类图
        • 3.4 具体实现
        • 3.5 工厂方法模式的优缺点
      • 四、抽象工厂模式
        • 4.1 模式定义
        • 4.2 模式结构
        • 4.3 类图
        • 4.4 具体实现
        • 4.5 抽象工厂模式的优缺点

一、关于GoF

  • 《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)是软件工程领域有关设计模式的一本书,提出和总结了对于一些常见软件设计问题的标准解决方案,称为软件设计模式。该书作者是埃里希·伽玛(Erich Gamma)、Richard Helm、Ralph Johnson和John Vlissides,后以“四人帮”(Gang of Four,GoF)著称,书中的设计模式也被称为“四人帮设计模式”(Gang of Four design patterns)。

  • 该书中描述了23种设计模式。我们平常所说的设计模式就是指这23种设计模式。

  • 不过除了GoF23种设计模式之外,还有其它的设计模式,比如:JavaEE的设计模式(DAO模式、MVC模式等)。

23种设计模式及其分类

创建范例

创建范例全部是关于如何创建实例的。这组范例可以被划分为两组:类创建范例及对象创建范例。类创建实例在实例化过程中有效的使用类之间的继承关系,对象创建范例则使用代理来完成其任务。

  • 抽象工厂 (Abstract Factory)
  • 构造器 (Builder Pattern)
  • 工厂方法 (Factory Method pattern)
  • 原型 (Prototype pattern)
  • 单例模式 (Singleton pattern)
结构范例

这组范例都是关于类及对象复合关系的。

  • 适配器(Adapter pattern)
  • 桥接(Bridge pattern)
  • 组合(Composite pattern)
  • 装饰(Decorator pattern)
  • 外观(Facade pattern)
  • 享元(Flyweight pattern)
  • 代理(Proxy pattern)
行为范例

这组范例都是关于对象之间如何通讯的。

  • 责任链(Chain-of-responsibility pattern)
  • 命令(Command pattern)
  • 翻译器(Interpreter pattern)
  • 迭代器(Iterator pattern)
  • 中介者(Mediator pattern)
  • 回忆(Memento pattern)
  • 观察者(Observer pattern)
  • 状态机(State pattern)
  • 策略(Strategy pattern)
  • 模板方法(Template method pattern)
  • 参观者(Visitor)

二、简单工厂模式(工厂方法的特殊形式)

2.1 模式定义

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

2.2 模式结构

  • Factory:工厂角色

    工厂角色负责实现创建所有实例的内部逻辑

  • Product:抽象产品角色

    抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口

  • ConcreteProduct:具体产品角色

    具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

2.3 类图

../_images/SimpleFactory.jpg

2.4 具体实现

目录结构如下:

image-20230625163639652

抽象产品角色:

package *com.hzzlovezq.abstractProduct*;public abstract class Fruit {public abstract void sell();
}

具体产品角色:

package com.hzzlovezq.specificProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Banana extends Fruit {@Overridepublic void sell() {System.out.println("出售一个香蕉~");}
}
package com.hzzlovezq.specificProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Orange extends Fruit {@Overridepublic void sell() {System.out.println("出售一个橙子~");}
}

工厂角色:

package com.hzzlovezq.factory;import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Banana;
import com.hzzlovezq.specificProduct.Orange;public class FruitFactory {public static Fruit getFruit(String fruitType){if ("ORANGE".equals(fruitType)) {return new Orange();} else if ("BANANA".equals(fruitType)){return new Banana();} else {throw new RuntimeException("本店不出售该水果!");}
//        return null;}
}

测试代码:

import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.factory.FruitFactory;
import org.junit.Test;public class SimpleFactoryTest {@Testpublic void testSell(){Fruit orange = FruitFactory.getFruit("ORANGE");orange.sell();Fruit banana = FruitFactory.getFruit("BANANA");banana.sell();}
}

测试结果:

image-20230625164026077

2.5 简单工厂模式的优缺点

优点:

客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责“消费”, 工厂负责“生产”。生产和消费分离。

缺点:

  • 工厂类集中了所有的逻辑创造,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,一旦出问题则整个系统瘫痪。
  • 简单工厂模式违反了开闭原则(OCP原则),在进行系统扩展时,需要修改工厂类。

三、工厂方法模式

3.1 模式定义

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

3.2 模式结构

  • 产品 (Product) 将会对接口进行声明。 对于所有由创建者及其子类构建的对象, 这些接口都是通用的。

  • 具体产品 (Concrete Products) 是产品接口的不同实现。

  • 创建者 (Creator) 类声明返回产品对象的工厂方法。 该方法的返回对象类型必须与产品接口相匹配。

    你可以将工厂方法声明为抽象方法, 强制要求每个子类以不同方式实现该方法。 或者, 你也可以在基础工厂方法中返回默认产品类型。

    注意, 尽管它的名字是创建者, 但它最主要的职责并不是创建产品。 一般来说, 创建者类包含一些与产品相关的核心业务逻辑。 工厂方法将这些逻辑处理从具体产品类中分离出来。 打个比方, 大型软件开发公司拥有程序员培训部门。 但是, 这些公司的主要工作还是编写代码, 而非生产程序员。

  • 具体创建者 (Concrete Creators) 将会重写基础工厂方法, 使其返回不同类型的产品。

    注意, 并不一定每次调用工厂方法都会创建新的实例。 工厂方法也可以返回缓存、 对象池或其他来源的已有对象。

3.3 类图

工厂方法模式结构

3.4 具体实现

目录结构如下:

image-20230625171106704

产品(抽象产品):

package *com.hzzlovezq.abstractProduct*;public abstract class Fruit {public abstract void sell();
}

具体产品:

package com.hzzlovezq.specificProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Banana extends Fruit {@Overridepublic void sell() {System.out.println("Sold a banana~");}
}	
package com.hzzlovezq.specificProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Orange extends Fruit {@Overridepublic void sell() {System.out.println("Sold an orange~");}
}
package com.hzzlovezq.specificProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Apple extends Fruit {@Overridepublic void sell() {System.out.println("Sold an apple~");}
}

创建者(抽象工厂):

package com.hzzlovezq.abstractFactory;import com.hzzlovezq.abstractProduct.Fruit;public interface FruitFactory {Fruit getFruit();
}

具体创建者(具体工厂):

package com.hzzlovezq.specificFactory;import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Banana;public class BananaFactory implements FruitFactory {@Overridepublic Fruit getFruit() {return new Banana();}
}
package com.hzzlovezq.specificFactory;import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Orange;public class OrangeFactory implements FruitFactory {@Overridepublic Fruit getFruit() {return new Orange();}
}
package com.hzzlovezq.specificFactory;import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Apple;public class AppleFactory implements FruitFactory {@Overridepublic Fruit getFruit() {return new Apple();}
}

测试代码:

import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificFactory.AppleFactory;
import com.hzzlovezq.specificFactory.BananaFactory;
import com.hzzlovezq.specificFactory.OrangeFactory;
import org.junit.Test;public class MethodFactoryTest {@Testpublic void methodTest(){FruitFactory bananaFactory = new BananaFactory();Fruit banana = bananaFactory.getFruit();banana.sell();FruitFactory orangeFactory = new OrangeFactory();Fruit orange = orangeFactory.getFruit();orange.sell();FruitFactory appleFactory = new AppleFactory();Fruit apple = appleFactory.getFruit();apple.sell();}
}

测试结果:

image-20230625171503377

3.5 工厂方法模式的优缺点

优点:

  • 你可以避免创建者和具体产品之间的紧密耦合。
  • 单一职责原则。 你可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护。
  • 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。

缺点:

应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。

四、抽象工厂模式

4.1 模式定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

4.2 模式结构

  • 抽象产品 (Abstract Product) 为构成系列产品的一组不同但相关的产品声明接口。
  • 具体产品 (Concrete Product) 是抽象产品的多种不同类型实现。 所有变体 (维多利亚/现代) 都必须实现相应的抽象产品 (椅子/沙发)。
  • 抽象工厂 (Abstract Factory) 接口声明了一组创建各种抽象产品的方法。
  • 具体工厂 (Concrete Factory) 实现抽象工厂的构建方法。 每个具体工厂都对应特定产品变体, 且仅创建此种产品变体。

4.3 类图

../_images/AbatractFactory.jpg

4.4 具体实现

目录结构如下:
在这里插入图片描述

抽象工厂:

package *com.hzzlovezq.abstractFactory*;import *com.hzzlovezq.abstractProduct.*Fruit;
import *com.hzzlovezq.abstractProduct.*Weapon;public abstract class AbstractFactory {public abstract Fruit getFruit(*String* *fruitType*);public abstract Weapon getWeapon(*String* *weaponType*);
}

具体工厂:

package com.hzzlovezq.concreteFactory;import com.hzzlovezq.abstractFactory.AbstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.abstractProduct.Weapon;
import com.hzzlovezq.concreteProduct.Apple;
import com.hzzlovezq.concreteProduct.Orange;public class FruitFactory extends AbstractFactory {@Overridepublic Fruit getFruit(String fruitType) {if ("ORANGE".equals(fruitType)) {return new Orange();} else if ("APPLE".equals(fruitType)) {return new Apple();} else {throw new RuntimeException("不出售该类水果!");}}@Overridepublic Weapon getWeapon(String weaponType) {return null;}
}
package com.hzzlovezq.concreteFactory;import com.hzzlovezq.abstractFactory.AbstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.abstractProduct.Weapon;
import com.hzzlovezq.concreteProduct.Apple;
import com.hzzlovezq.concreteProduct.Dagger;
import com.hzzlovezq.concreteProduct.Gun;
import com.hzzlovezq.concreteProduct.Orange;public class WeaponFactory extends AbstractFactory {@Overridepublic Fruit getFruit(String fruitType) {return null;}@Overridepublic Weapon getWeapon(String weaponType) {if ("GUN".equals(weaponType)) {return new Gun();} else if ("DAGGER".equals(weaponType)) {return new Dagger();} else {throw new RuntimeException("不出售该类水果!");}}
}

抽象产品:

package com.hzzlovezq.abstractProduct;public abstract class Fruit {public abstract void sell();
}
package com.hzzlovezq.abstractProduct;public abstract class Weapon {public abstract void attack();
}

具体产品:

package com.hzzlovezq.concreteProduct;import com.hzzlovezq.abstractProduct.Weapon;public class Gun extends Weapon {@Overridepublic void attack() {System.out.println("给你一梭子~");}
}
package com.hzzlovezq.concreteProduct;import com.hzzlovezq.abstractProduct.Weapon;public class Dagger extends Weapon {@Overridepublic void attack() {System.out.println("戳死你~");}
}
package com.hzzlovezq.concreteProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Apple extends Fruit {@Overridepublic void sell() {System.out.println("卖了一个苹果~");}
}
package com.hzzlovezq.concreteProduct;import com.hzzlovezq.abstractProduct.Fruit;public class Orange extends Fruit {@Overridepublic void sell() {System.out.println("卖了一个橙子~");}
}

测试代码:

import com.hzzlovezq.abstractFactory.AbstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.abstractProduct.Weapon;
import com.hzzlovezq.concreteFactory.FruitFactory;
import com.hzzlovezq.concreteFactory.WeaponFactory;
import org.junit.Test;public class AbstractFactoryTest {@Testpublic void abstractTest(){// 客户端调用方法时只面向AbstractFactory调用方法。AbstractFactory factory = new WeaponFactory(); // 注意:这里的new WeaponFactory()可以采用 简单工厂模式 进行隐藏。Weapon gun = factory.getWeapon("GUN");Weapon dagger = factory.getWeapon("DAGGER");gun.attack();dagger.attack();AbstractFactory factory1 = new FruitFactory(); // 注意:这里的new FruitFactory()可以采用 简单工厂模式 进行隐藏。Fruit orange = factory1.getFruit("ORANGE");Fruit apple = factory1.getFruit("APPLE");orange.sell();apple.sell();}
}

运行结果:

image-20230625175006770

4.5 抽象工厂模式的优缺点

优点:

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:

产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码。

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

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

相关文章

git常见操作汇总

存档,方便本人查询~ 除了add、commit、push、pull外有些操作也是需要掌握的~在复习之前先准备一下需要的项目: mkdir git-demo1 cd git-demo1 git init基础操作 # 在工作区新增一个README.md文件,并写入 # Hello World# 查看哪些原件做了修…

实验篇(7.2) 17. 站对站安全隧道 - FortiGate作为SSL客户端(SSL) ❀ 远程访问

【简介】虽然常用的站到站的连接用的是IPsec VPN,但是在某些特殊情况下,UDP500或4500端口被阻断,IPsec VPN无法连接,那么还有其它办法实现站到站的连接吗?SSL VPN也可以的。 实验要求与环境 OldMei集团深圳总部部署了域…

c#调用c++ dll,Release版本内存访问错误

最近遇到个比较经典的案例,在c#中调用yara进行文件检测,yara是c编写的一个非常强大库,github有个大佬用c#对其进行了封装,使其能在跨平台下,只需编译yara的so或dll就能直接跑。但总是在Release版本下时不时就崩溃&…

全网独家--【图像色彩增强】方法梳理和问题分析

文章目录 图像增强图像色彩增强问题可视化比较 难点色彩空间大,难以准确表征?不同场景差异大,难以自适应?计算量大,但应用场景往往实时性要求高? 方法传统方法深度学习逐像素预测3D LUT模仿ISP 个人思考批判…

PDF怎么转图片?PDF转图片的方法分享!​

PDF怎么转图片呢?相信很多人都会觉得PDF的非常的好用,小编也是被身边很多朋友推荐过后用了这个软件。但很多人在使用的时候有疑问,比如说PDF如何转图片?这难倒不少人,那么今天这篇文章就带你解析PDF怎么转图片&#xf…

CSS知识点汇总(八)--Flexbox

1. flexbox(弹性盒布局模型)是什么,适用什么场景? 1. flexbox(弹性盒布局模型)是什么 Flexible Box 简称 flex,意为”弹性布局”,可以简便、完整、响应式地实现各种页面布局。采用…

docker 安装

CentOS Docker 安装 | 菜鸟教程 或者官网 docker安装要求: Docker要求CentOS系统的内核版本高于 3.10 ,通过 uname -r 命令查看你当前的内核版本是否支持安账docker。 第二步 sudo yum update 在给yum打补丁的时候 中需要有一次y 确定 …

Maven下载安装及其配置

Maven下载安装及其配置 文章目录 Maven下载安装及其配置1、Maven介绍2、Maven下载安装2.1、最新2.2、旧版3.8 3、Maven环境配置3.1、配置3.2、验证3.3、 配置本地仓库 4、Maven使用4.1、Maven常用命令4.2、IDEA中的使用 1、Maven介绍 Maven 是一个流行的构建工具和依赖管理工具…

【单片机】STM32单片机,RTC实时时钟,STM32F103C8T6,程序,万年历,数字时钟

文章目录 基础介绍rtc.hrtc.cmain.c 基础介绍 我以STM32F103C8T6为例,但STM32F103的RTC是通用的,STM32F103C8T6有一个原理图: https://qq742971636.blog.csdn.net/article/details/131288390 用纽扣电池给VBAT供电(要共地&…

分布式操作系统期末复习(辽宁大学王龙主讲)

目录 一、题目 1.1 简答题 1.2 综合题 二、题目答案 2.1 简答题目答案 2.2 综合题目答案 三、期末题型分值分布 3.2 题型和分值 一、题目 1.1 简答题 1什么是中间件 22.1(22年期末考试第一题) 2 什么是名称解析 3 描述一下客户和服务器之间使…

论文阅读 - SegFormer

文章目录 1 概述2 模型说明2.1 总体结构2.2 Hierarchical Transformer Encoder2.3 Lightweight All-MLP Decoder 3 SegFormer和SETR的比较参考资料 1 概述 图像分割任务和图像分类任务是非常相关的,前者是像素级别的分类,后者是图像级别的分类。基于分类…

第37节:cesium 下雪效果(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><vc-viewer @ready="ready" :logo="false"><!