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

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

参考文献/文章地址:

  • 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 {
    @Override
    public void sell() {
        System.out.println("出售一个香蕉~");
    }
}
package com.hzzlovezq.specificProduct;

import com.hzzlovezq.abstractProduct.Fruit;

public class Orange extends Fruit {
    @Override
    public 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 {
    @Test
    public 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 {
    @Override
    public void sell() {
        System.out.println("Sold a banana~");
    }
}	
package com.hzzlovezq.specificProduct;

import com.hzzlovezq.abstractProduct.Fruit;

public class Orange extends Fruit {
    @Override
    public void sell() {
        System.out.println("Sold an orange~");
    }
}
package com.hzzlovezq.specificProduct;

import com.hzzlovezq.abstractProduct.Fruit;

public class Apple extends Fruit {
    @Override
    public 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 {

    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public 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 {
    @Test
    public 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 {
    @Override
    public Fruit getFruit(String fruitType) {
        if ("ORANGE".equals(fruitType)) {
            return new Orange();
        } else if ("APPLE".equals(fruitType)) {
            return new Apple();
        } else {
            throw new RuntimeException("不出售该类水果!");
        }
    }

    @Override
    public 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 {
    @Override
    public Fruit getFruit(String fruitType) {
        return null;
    }

    @Override
    public 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 {

    @Override
    public void attack() {
        System.out.println("给你一梭子~");
    }
}

package com.hzzlovezq.concreteProduct;

import com.hzzlovezq.abstractProduct.Weapon;

public class Dagger extends Weapon {
    @Override
    public void attack() {
        System.out.println("戳死你~");
    }
}

package com.hzzlovezq.concreteProduct;

import com.hzzlovezq.abstractProduct.Fruit;

public class Apple extends Fruit {
    @Override
    public void sell() {
        System.out.println("卖了一个苹果~");
    }
}
package com.hzzlovezq.concreteProduct;

import com.hzzlovezq.abstractProduct.Fruit;

public class Orange extends Fruit {
    @Override
    public 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 {
    @Test
    public 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里加代码,又要在具体的里面加代码。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

el-table合计行单元格合并、单元格样式修改

1、目标效果 源码放在下面,复制粘贴即可 (1)合计行放在头部,且字体颜色变粗、合计行背景色变粗 (2)合计行年龄算平均值且字体颜色为绿色,财产算总数且字体颜色为红色 2、原理 2.1、el-table中s…

WPF 零基础入门笔记(1):WPF静态页面,布局+样式+触发器

文章目录 官方文档往期回顾零基础笔记项目实战(已完结) WPF项目创建为什么选net core版本 WPF 静态页面WPF 页面布局WPF样式Style样式行内样式行外样式如果是简单样式,可以这么写如果是复杂样式 WPF样式继承WPF触发器单条件触发器多条件触发 …

【性能测试一】性能测试概述

目录 🌟一、性能测试的基础概念 🌈1、生活中软件相关的性能问题? 🌈2、性能测试的概念 🌈3、性能测试与功能测试的区别? 🌈4、什么样的软件属于性能好?什么样的软件属于性能不好…

网络协议TCP/IP 协议学习笔记一

T C P / I P通常被认 为是一个四层协议系统,每一层负责不同的功能: 1) 链路层,有时也称作数据链路层或网络接口层, 通常包括操作系统中的设备驱动程序和计算机 中对应的网络接口卡。它们一起处理与电缆(或其他任何传输…

黑客常用cmd命令(window版)

1、ping命令 ping命令是一个常用的网络工具,用来测试和诊断网络连接状况。通过发送ICMP(Internet控制消息协议)数据包到目标主机,并接收回复的数据包,可以测量目标主机的可达性、平均响应时间等指标。 在Windows操作…

【C++】哈希的应用

文章目录 一、位图1. 位图的引入2. 位图的实现3. 位图的应用4. 哈希切割 二、布隆过滤器1. 布隆过滤器的引入2. 布隆过滤器的实现3. 布隆过滤器的应用4. 布隆过滤器的总结 一、位图 1. 位图的引入 我们先来看一道面试题: 给40亿个不重复的无符号整数,没…

Spring Boot 如何使用 @RequestParam 进行数据校验

Spring Boot 如何使用 RequestParam 进行数据校验 在 Web 应用程序中,用户提交的数据通常以请求参数的形式传递。在 Spring Boot 中,可以使用 RequestParam 注解来获取请求参数。但是,如何确保这些请求参数的有效性呢?在本文中&a…

APP测试面试题快问快答(五)

21. App自动化你用的什么工具? 框架:Appium 编译环境和工具:python3.7和PyCharm 环境:Android sdk 第三方模拟器:夜神、蓝叠等模拟器 定位工具:uiautomatorviewer 实时日志查看:ddms 22.…

智慧加油站卸油作业行为分析算法 opencv

智慧加油站卸油作业行为分析系统通过opencvpython网络模型技术,智慧加油站卸油作业行为分析算法实现对卸油作业过程的实时监测。当现场出现卸油作业时人员离岗,打电话人员抽烟等违规行为,灭火器未正确摆放,明火和烟雾等异常状态&a…

TypeScript零基础入门之背景介绍和环境安装

一、什么是TypeScript TypeScript是一种由微软开发和维护的开源编程语言。它是JavaScript的超集,意味着任何JavaScript程序都是一种有效的TypeScript程序。TypeScript添加了静态类型、类、接口、枚举和命名空间等概念,同时支持ES6特性。TypeScript被视为…

Kubernetes入门实战课-初始容器

Kubernetes入门实战课-初始容器 文章目录 Kubernetes入门实战课-初始容器课前准备初始容器Docker 的形态Docker 的安装Docker 的架构 容器的本质隔离原因与虚拟机区别隔离是怎么实现的 镜像创建容器镜像:如何编写正确、高效的Dockerfile镜像的内部机制是什么Dockerf…

Spring介绍

⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐作者主页:逐梦苍穹 ⭐所属专栏:JavaEE、Spring 目录 1、Spring简介2、轻量级和非侵入性3、IoC容器4、AOP支持5、声明式事务管理6、数据访问支持…

【基于Django框架的在线教育平台开发-02】用户注册功能开发

用户注册功能开发 文章目录 用户注册功能开发1 模型层开发2 视图层开发3 配置urls.py4 表单验证5 模板层开发6 效果展示 1 模型层开发 用户数据表如下所示: FieldTypeExtraidintPrime Key & Auto Incrementpasswordvarchar(128)last_logindatetime(6)Allow Nu…

第八章 模型篇:transfer learning for computer vision

参考教程: transfer-learning transfer-learning tutorial 文章目录 transfer learning对卷积网络进行finetune把卷积网络作为特征提取器何时、如何进行fine tune 代码示例加载数据集构建模型fine-tune 模型模型作为feature extractor 定义train_loop和test_loop定…

Docker常见使用

Docker常见使用 1、Docker安装 ## 下载阿里源repo文件 $ curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo $ curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo$ yum clean …

工业相机的镜头如何选择?

相机的镜头如何计算,如果看公式的话,需要知道相机sensor的尺寸,相元的尺寸,计算起来数据也比较复杂,下面教大家一个简单的方法,就是如何借助镜头计算工具来使用。 巴斯勒相机的镜头选型地址 工业镜头选型…

操作系统之死锁详解

本文已收录于专栏 《自考》 目录 背景介绍死锁的前提死锁的概念死锁的分类死锁的产生原因条件 死锁的解决预防避免检测与恢复 死锁的实现总结提升 背景介绍 最近一直在做操作系统的测试题,在做题的过程中发现有很多地方涉及到了关于死锁的知识点。今天就回归课本来自…

哈工大计算机网络课程网络层协议详解之:网络地址转换NAT

哈工大计算机网络课程网络层协议详解之:网络地址转换NAT 文章目录 哈工大计算机网络课程网络层协议详解之:网络地址转换NAT网络地址转换(NAT)NAT实现原理NAT穿透问题NAT穿透问题的解决方案 上一节中,我们在DHCP协议中介…

【人脸检测——基于机器学习4】HOG特征

前言 HOG特征的全称是Histograms of Oriented Gradients,基于HOG特征的人脸识别算法主要包括HOG特征提取和目标检测,该算法的流程图如下图所示。本文主要讲HOG特征提取。 HOG特征的组成 Cell:将一幅图片划分为若干个cell(如上图绿色框所示),每个cell为8*8像素 Block:选…

【力扣刷题 | 第十四天】

目录 前言: 7. 整数反转 - 力扣(LeetCode) 面试题 16.05. 阶乘尾数 - 力扣(LeetCode) 总结; 前言: 今天仍然是无固定类型刷题, 7. 整数反转 - 力扣(LeetCode) 给你…