设计模式-工厂模式的完整代码示例及测试验证

news2024/9/22 15:29:59

工厂模式

工厂模式

什么是工厂模式?

工厂模式是一种创建对象的设计模式,用来替代传统的 如 A a=new A() 创建对象的方式,提供了一种 统一的接口来创建对象,
封装创建的过程,达到解耦的目的。


优缺点

  • 优点
  1. 封装对象的创建过程:工厂类将对象创建的细节封装起来,客户端无需关心实例化的具体过程,简化了代码。
  2. 提高代码的可维护性:由于实例化逻辑集中在工厂类中,如果需要更改对象的创建逻辑,只需修改工厂类,不必修改客户端代码。
  3. 解耦,通过工厂接口来创建对象,而不用关注对象的具体实现(不用关心 a的具体实现A a = new A 还是 A a = new AFather())使得代码更易于扩展和维护。
  4. 支持多态和接口编程:可以返回父类或接口的对象,使得代码更加灵活,符合“依赖倒置原则”。
  • 缺点
  1. 增加了系统的复杂性:引入工厂类会增加类的数量和代码的复杂度,对于简单的应用场景可能显得多余。
  2. 可能导致过度设计:在不需要复杂对象创建逻辑的情况下,使用工厂模式可能导致代码显得臃肿和过度设计
  3. 可能难以管理:当工厂类需要处理很多具体类的创建时,工厂类本身可能变得复杂和难以管理。

工厂模式的分类

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

简单工厂模式(Simple Factory)

假设我们有两种动物类:Dog 和 Cat,和一个动物的接口类Animal,他们都有“说”的方法

public interface Animal {
    //动物接口,公共的 说的方法
    void speak();
}
public class Dog implements Animal{
    @Override
    public void speak() {
        System.out.println("我是旺财,汪!汪!汪!");
    }
}

public class Cat implements Animal{

    @Override
    public void speak() {
        System.out.println("我是喵星人,喵!喵!喵!");
    }
}

传统方式的使用

    /**
     * 传统模式
     *    优点:简单直接
     *    缺点:
     *       高耦合:如果新来了牛马,那么就得在所有业务处去写 
 *           形如  Animal hors = new Horse() 的具体对象创建
     *       不利于扩展
     */
    @Test
    public void useTraditionTest(){
        //传统调用测试

        //创建一只狗对象,并调用讲话的方法
        Animal dog = new Dog();
        dog.speak();//输出我是旺财,汪!汪!汪!

        //创建一只猫对象,并调用讲话的方法
        Animal cat = new Cat();
        cat.speak();//我是喵星人,喵!喵!喵
        
        // ... 以及未来新到来的牛马们
    }

简单工厂方式的使用

  • 创建简单工厂类,用来创建动物实例
public class AnimalFactory {
    public static Animal getAnimal(String type){
        //把创建对象的细节封装在工厂类的方法里,统一向外暴露
        Animal animal = null;
        //根据传入的type参数,创造不同的动物实例
        if ("dog".equalsIgnoreCase(type)) {
            animal = new Dog();
        } else if ("cat".equalsIgnoreCase(type)) {
            animal = new Cat();
        }
        return animal;
    }
}

  • 简单工厂的使用
    /**
     * 简单工厂模式
     *    优点:
     *       低耦合:厂类来封装对象的创建过程,业务处代码不依赖具体类的实现,只需知道工厂类和接口。
     *       灵活性:可以在工厂类中轻松添加新类型的对象,客户端代码繁琐重复创建。
     *    缺点:
     *       工厂类过于复杂:随着对象种类的增加,工厂类会变得复杂和臃肿。
     *       不符合开闭原则:每次新增一种牛马类都需要修改工厂类代码。
     */
    @Test
    public void useSimpleFactoryTest(){
        //通过简单工厂获取狗对象,并调用讲话的方法
        Animal dog = AnimalFactory.getAnimal("dog");
        dog.speak();输出我是旺财,汪!汪!汪!

        //通过简单工厂获取猫对象,并调用讲话的方法
        Animal cat = AnimalFactory.getAnimal("cat");
        cat.speak();我是喵星人,喵!喵!喵
    }


由于简单工厂模式的缺点,每新增一种牛马,就需要修改工厂类代码,当牛马类型太多时,
造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有牛马创建逻辑,一旦有牛马出现意外,
整个牛马厂都要歇菜,创建都要受到影响(这不就是中央到分布式的思想么),基于此引入了工厂方法模式。


工厂方法模式(Factory Method)

在工厂方法模式中,我们定义一个工厂接口,为每一种动物创建一个工厂去实现工厂接口,因为在现实生活中,
会存在很牛马,比如牛啊,马啊,猪啊,驴啊等等我们可以把他们的实例创建统一到狗子工厂中,便于维护和管理。


  • 创建动物工厂

public interface AnimalFactoryInter {

    //创建牛马的工厂接口
    Animal createAnimal();
}

  • 创建旺财工厂,实现动物工厂

public class DogFactory implements AnimalFactoryInter {
    @Override
    public Animal createAnimal() {
        //旺财工厂,专门创造狗子
        return new Dog();
    }
}

  • 创建猫星人工厂,实现动物工厂
public class CatFactory implements AnimalFactoryInter {
    @Override
    public Animal createAnimal() {
        //猫星人工厂,专门创造喵喵
        return new Cat();
    }
}

  • 工厂方法的使用

    /**
 * 工厂方法模式
 *    优点:
 *       遵循开闭原则:添加新类型的对象时,只需创建新的具体工厂类,无需修改现有代码。
 *       符合单一职责原则:每个具体工厂类只负责创建一种特定类型的对象。
 *       灵活性高:客户端代码依赖于抽象的工厂接口,可以在运行时选择具体的工厂实现。
 *    缺点:
 *       增加类的数量:每增加一种新类型的对象,都需要增加一个具体工厂类,可能会导致类的数量增加。
 *       代码复杂度增加:相比于简单工厂模式,工厂方法模式的代码结构更加复杂。
 */
@Test
public void useFactoryMethodTest(){
    //工厂方法调用方式

    //通过旺财工厂,创造狗子
    AnimalFactoryInter dogFactory = new DogFactory();
    Animal dog = dogFactory.createAnimal();
    dog.speak();//输出我是旺财,汪!汪!汪!

    //通过喵星人工厂,创造喵喵喵
    AnimalFactoryInter catFactory = new CatFactory();
    Animal cat = catFactory.createAnimal();
    cat.speak();//我是喵星人,喵!喵!喵
}


由于工厂方法模式的缺点,抽象工厂只能创建一种产品,即AnimalFactoryInter抽象工厂只能去创建动物,所以引入了抽象工厂模式,
他其实是工厂方法的一种扩展,就是在这个抽象工厂中提供多个抽象方法,除了提供创造动物的方法,还提供创造食物的方法,
再由具体的食物工厂去实现,这样当我们就可以给旺财喂点大棒骨,给喵星人喂条小咸鱼的功能了,基于此引入抽象工厂模式


抽象工厂模式(Abstract Factory)

    在抽象工厂模式中,有两个抽象层次:抽象工厂和具体工厂。抽象工厂定义了一个或多个工厂方法,用于创建一组相关或依赖的产品对象。
具体工厂实现了抽象工厂中定义的工厂方法,负责创建具体的产品对象。与工厂方法模式相比,抽象工厂模式更加灵活,可以创建一组相关的产品对象,
并且可以在不修改客户端代码的情况下改变所创建的产品组合。同时,抽象工厂模式也更加复杂,因为它需要定义多个工厂方法和相关的产品接口。

在抽象工厂模式中,涉及一个需要了解的知识点

  1. 产品等级结构:产品等级结构指的是产品的继承结构,比如生活方式等级,可以有1号人生的等级,2号人生等级,在每个等级结构中,包含了产品族中具体的产品类
    如:生产一只金毛狗(Dog),生产一只大棒骨(DogFood),生成一套总统套房的狗窝(DogHouse),实现产品族中具体的工厂生成类(DogFactory)
    动物这一产品等级
  2. 产品族:一组相关的产品对象,它们通常是一起使用的,并且由同一个工厂类创建。例如,动物工厂中的产品族可以包括狗和猫。如定义Animal动物产品,在动物产品族中
    会生成出金毛狗,折耳猫,拉磨驴等不同种类的产品

结构图:

在这里插入图片描述

如果动物这个例子不太容易理解,可以再增加一个产品的例子,把冰箱、空调、电视对应为产品,把美的品牌、格力品牌、海尔品牌对应为生产的工厂
那么 美的工厂生产的冰箱、空调、电视 就是一个产品族(产品家族,这个品牌有很多种类的产品),
而美的冰箱、格力冰箱、海尔冰箱形成一个产品等级结构(同一种产品有1级,2级,3级区别,也知道谁是冰箱等级里的老大)

结构图:
在这里插入图片描述


  • 新增食物接口
public interface Food {
    //食物接口,公共的 吃的方法
    void eat();
}
  • 旺财相关具体的食物类,

public class DogFood implements Food{

    @Override
    public void eat() {
        System.out.println("我是给旺财专供的大棒骨!");
    }
}

  • 喵星人相关的食物类
public class CatFood implements Food{

    @Override
    public void eat() {
        System.out.println("我是给喵星人专供的小咸鱼!");
    }
}
  • 在动物工厂(也可称为超级工厂)中新增 生产食物的方法
public interface AnimalFactoryInter {

    //创建牛马的工厂接口
    Animal createAnimal();

    //定义牛马们吃饭的接口
    Food createFood();
}

  • 在狗工厂中来实现 食物的生产
public class DogFactory implements AnimalFactoryInter {
    @Override
    public Animal createAnimal() {
        //旺财工厂,专门创造狗子
        return new Dog();
    }

    @Override
    public Food createFood() {
        //旺财工厂,专门创造狗粮
        return new DogFood();
    }
}

  • 在猫工厂中来实现 食物的生产
public class CatFactory implements AnimalFactoryInter {
    @Override
    public Animal createAnimal() {
        //猫星人工厂,专门创造喵喵
        return new Cat();
    }

    @Override
    public Food createFood() {
        //猫星人工厂,专门创造猫粮
        return new CatFood();
    }
}

  • 抽象工厂的使用
    /**
     * 抽象工厂模式
     *    优点:
     *       符合开闭原则:添加新产品族(增加鸟类)时,只需增加新的具体工厂类和相应的产品类,不需要修改现有代码。
     *       高内聚低耦合:具体工厂类负责创建相关产品的对象,从而使客户端代码与具体工厂类的实现细节解耦。
     *       增强产品族的一致性:确保一个产品族中的产品对象在创建时的一致性。
     *    缺点:
     *       复杂性增加:与简单工厂和工厂方法模式相比,抽象工厂模式需要更多的类和接口,代码结构更复杂。
     *       扩展产品等级结构困难:添加新的产品类型(例如,在已有的动物和食物的基础上,再添加一个新的房子类),
     *       则需要修改抽象工厂接口,添加新的方法以创建新的产品类型,同时修改所有的具体工厂类以实现新的方法
     */
    @Test
    public void useAbstractFactoryTest(){
        //抽象工厂 调用方式

        //通过工厂,创造狗子,并生产狗粮
        AnimalFactoryInter dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        Food dogFood = dogFactory.createFood();;
        dog.speak();//我是旺财,汪!汪!汪!
        dogFood.eat();//我是给旺财专供的大棒骨!

        //通过工厂,创造喵星人,并生产猫粮
        AnimalFactoryInter catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        Food catFood = catFactory.createFood();;
        cat.speak();//我是喵星人,喵!喵!喵!
        catFood.eat();//我是给喵星人专供的小咸鱼!
    }
    

完整调用测试示例

public class UseTest {

    /**
     * 传统模式
     *    优点:简单直接
     *    缺点:
     *       高耦合:如果新来了牛马,那么就得在所有业务处去写 形如  Animal hors = new Horse() 的具体对象创建
     *       不利于扩展
     */
    @Test
    public void useTraditionTest(){
        //传统调用测试

        //创建一只狗对象,并调用讲话的方法
        Animal dog = new Dog();
        dog.speak();//输出我是旺财,汪!汪!汪!

        //创建一只猫对象,并调用讲话的方法
        Animal cat = new Cat();
        cat.speak();//我是喵星人,喵!喵!喵

        // ... 以及未来新到来的牛马们
    }


    /**
     * 简单工厂模式
     *    优点:
     *       低耦合:厂类来封装对象的创建过程,业务处代码不依赖具体类的实现,只需知道工厂类和接口。
     *       灵活性:可以在工厂类中轻松添加新类型的对象,客户端代码繁琐重复创建。
     *    缺点:
     *       工厂类过于复杂:随着对象种类的增加,工厂类会变得复杂和臃肿。
     *       不符合开闭原则:每次新增产品类都需要修改工厂类代码。
     */
    @Test
    public void useSimpleFactoryTest(){
        //简单工厂调用方式

        //通过简单工厂获取狗对象,并调用讲话的方法
        Animal dog = AnimalFactory.getAnimal("dog");
        dog.speak();//输出我是旺财,汪!汪!汪!

        //通过简单工厂获取猫对象,并调用讲话的方法
        Animal cat = AnimalFactory.getAnimal("cat");
        cat.speak();//我是喵星人,喵!喵!喵
    }


    /**
     * 工厂方法模式
     *    优点:
     *       遵循开闭原则:添加新类型的对象时,只需创建新的具体工厂类,无需修改现有代码。
     *       符合单一职责原则:每个具体工厂类只负责创建一种特定类型的对象。
     *       灵活性高:客户端代码依赖于抽象的工厂接口,可以在运行时选择具体的工厂实现。
     *       多态性的应用:使得客户端代码可以统一通过抽象工厂类来调用工厂方法,而具体的工厂子类根据需求返回不同的产品对象,实现了对象的动态切换和灵活性。
     *    缺点:
     *       增加类的数量:每增加一种新类型的对象,都需要增加一个具体工厂类,可能会导致类的数量增加。
     *       代码复杂度增加:相比于简单工厂模式,工厂方法模式的代码结构更加复杂。
     */
    @Test
    public void useFactoryMethodTest(){
        //工厂方法调用方式

        //通过旺财工厂,创造狗子
        AnimalFactoryInter dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        dog.speak();//输出我是旺财,汪!汪!汪!

        //通过喵星人工厂,创造喵喵喵
        AnimalFactoryInter catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        cat.speak();//我是喵星人,喵!喵!喵
    }

    /**
     * 抽象工厂模式
     *    优点:
     *       符合开闭原则:添加新产品族(增加鸟类)时,只需增加新的具体工厂类和相应的产品类,不需要修改现有代码。
     *       高内聚低耦合:具体工厂类负责创建相关产品的对象,从而使客户端代码与具体工厂类的实现细节解耦。
     *       增强产品族的一致性:确保一个产品族中的产品对象在创建时的一致性。
     *    缺点:
     *       复杂性增加:与简单工厂和工厂方法模式相比,抽象工厂模式需要更多的类和接口,代码结构更复杂。
     *       扩展产品等级结构困难:添加新的产品类型(例如,在已有的动物和食物的基础上,再添加一个新的房子类),
     *       则需要修改抽象工厂接口,添加新的方法以创建新的产品类型,同时修改所有的具体工厂类以实现新的方法
     */
    @Test
    public void useAbstractFactoryTest(){
        //抽象工厂 调用方式

        //通过工厂,创造狗子,并生产狗粮
        AnimalFactoryInter dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        Food dogFood = dogFactory.createFood();;
        dog.speak();//我是旺财,汪!汪!汪!
        dogFood.eat();//我是给旺财专供的大棒骨!

        //通过工厂,创造喵星人,并生产猫粮
        AnimalFactoryInter catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        Food catFood = catFactory.createFood();;
        cat.speak();//我是喵星人,喵!喵!喵!
        catFood.eat();//我是给喵星人专供的小咸鱼!
    }
}

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

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

相关文章

pytorch官网examples 实现

Getting started with transforms v2 — Torchvision 0.18 documentation (pytorch.org) 官网我导入包都报错官网代码如下: 不太理解所以我自己写了一段修改之后的代码,效果是一样的 import torch from torchvision.io import read_image import mat…

X用户最多的国家排名统计报告

数据为DataReportal发布的Twitter在各个国家的用户数统计。 2022年,Twitter用户最多的国家是美国,有7690万用户。 数据统计单位为:万人 数据说明: 数据截止时间为2022年1月 Twitter在各个国家的用户情况 2022年,Twit…

【TES807】 基于XCKU115 FPGA的双FMC接口万兆光纤传输信号处理平台

板卡概述 TES807是一款基于千兆或者万兆以太网传输的双FMC接口信号处理平台。该平台采用XILINX的Kintex UltraSacle系列FPGA:XCKU115-2FLVF1924I作为主处理器,FPGA外挂两组72位DDR4 SDRAM,用来实现超大容量数据缓存,DDR4的最高数据…

RIP路由协议概述

RIP【Routing Information Protocol】 RIP是为TCP/IP 环境中开发的第一个路由选择协议标准 RIP是一个【距离——矢量】路由选择协议 当路由器的更新周期为30s到来时,向邻居发送路由表 RIP以跳数作为唯一度量值 RIP工作原理 RIP路由协议向邻居发送整个路由表信息RI…

《昇思25天学习打卡营第1天|QuickStart》

说在前面 曾经接触过华为的910B服务级显卡,当时基于910B做了一些开发的工作,但是总感觉做的事情太低层,想要能自顶向下的了解下,因此开始了MindSpore的学习。另外也想给予提供的显卡,简单尝试下llm模型的训练&#xf…

2.2 类型转换与 printf 函数深度解析

1 类型转换 1.1 隐式类型转换 1.2 显式类型转换 1.3 应用:整除除法 2 printf 函数 2.1 语法格式 2.2 格式说明符 2.2.1 浮点数的规范性输出 2.2.2 格式说明符不匹配错误 2.3 修饰符 2.3.1 对齐方式 2.3.2 宽度 2.3.3 精度 2.3.4 填充字符 2.3.5 其他修…

【硬件调试】示波器探头一碰芯片引脚板子就短路或者闪小火花

问题: 今天拿示波器探头准备测量芯片引脚输出波形,有的引脚正常输出信号,有的会打小火花,但输出波形正常,还有一个引脚最离谱,示波器一碰,板子就立马短路,电流达到最大值,电源电压都被拉下来了,直到示波器探头拿开,板子才自动恢复,此时这个引脚测得波形如下: 根…

C++的链接指示extern “C“

目录 链接指示extern "C"A.What(概念)B.Why(extern "C"的作用)C.How (如何使用链接指示extern "C") 链接指示extern “C” A.What(概念) extern&quo…

100 个网络基础知识普及,看完成半个网络高手!

1)什么是链接? 链接是指两个设备之间的连接。它包括用于一个设备能够与另一个设备通信的电缆类型和协议。 2)OSI 参考模型的层次是什么? 有 7 个 OSI 层:物理层,数据链路层,网络层&#xff0…

ElasticSearch第一天

学习目标: 能够理解ElasticSearch的作用能够安装ElasticSearch服务能够理解ElasticSearch的相关概念能够使用Postman发送Restful请求操作ElasticSearch能够理解分词器的作用能够使用ElasticSearch集成IK分词器能够完成es集群搭建 第一章 ElasticSearch简介 1.1 什么…

javaweb个人主页设计(html+css+js)

目录 1 前言和要求 1.1 前言 1.2 设计要求 2 预览 2.1 主页页面 2.2 个人简介 2.3 个人爱好 2.4 个人成绩有代码,但是图片已省略,可以根据自己情况添加 2.5 收藏夹 3 代码实现 3.1 主页 3.2 个人简介 3.3 个人爱好 3.4 个人成绩&#xff…

shell 字符串列表操作

我的需求是这样的:编译多个模块的时候,把失败的模块添加到列表里,最后输出。这个列表类似这样:failModuleList"a b c d e" 先定义一个空的字符串列表: failModuleList"" 然后利用字符串的拼接方…

CVPR`24 | 又快又好!渲染速度比ENeRF快30倍!4K4D:实时4K分辨率4D视图合成

文章链接:https://arxiv.org/pdf/2310.11448 git链接: https://zju3dv.github.io/4k4d/ 本文旨在实现动态3D场景在4K分辨率下的高保真和实时视图合成。最近,一些动态视图合成方法在渲染质量方面表现出色。然而,在渲染高分辨率图像…

如何合并pdf文件?分享3种常见的方法!

在数字化办公日益普及的今天,PDF文件因其格式稳定、兼容性强、阅读方便等特点,成为了人们日常工作和学习中不可或缺的一部分。然而,当我们需要处理多个PDF文件时,如何将它们高效地合并成一个文件,以便更好地管理和分享…

Linux进程——进程的概念

文章目录 PCB进程排队进程标识符pid终止进程获取进程id父进程与子进程 我们在上一节内容中有简单谈到进程的感性理解,他在课本上的概念是,程序的一个执行实例或正在执行的程序 但在本质上,他其实就是一个被分配了系统资源(CPU&am…

公有云API常见的认证方式

公有云API常见的认证方式 Token认证 (百度云、腾讯云) AK/SK认证 (阿里云、天翼云、腾讯云) RSA非对称加密方式 (信核云灾备) Token认证 AK/SK认证 RSA认证 种方式使用一对密钥,即公钥和私钥。公钥可以公开&#x…

Java数据结构-链表与LinkedList

链表 链表的概念 链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。 通俗来说,相比较于顺序表(物理上连续,逻辑上也连续),链表物理上不一定连续。 链表是…

【C++航海王:追寻罗杰的编程之路】一篇文章带你认识哈希

目录 1 -> unordered系列关联式容器 1.1 -> unordered_map 1.1.1 -> unordered_map的文档介绍 1.1.2 -> unordered_map的接口说明 1.2 -> unordered_set 2 -> 底层结构 2.1 -> 哈希概念 2.2 -> 哈希冲突 2.3 -> 哈希函数 2.4 -> 哈希冲…

Mysql进阶(一)——存储引擎

MySQL体系结构 1). 连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程 池的概念,为通过认证安全接入的…

【启明智显分享】ESP32-S3 4.3寸触摸串口屏HMI应用方案:WIFI/蓝牙无线通信助力烘干设备实现远程遥控

技术不断进步,人们对烘干设备的美观度、功能多样性提出更高要求,传统的数码管显示、按键式控制已经无法满足客户的需求。用智能屏替代传统的数码管可以很好的解决这个问题,为用户带来更好的人机交互体验。 基于此,启明智显提出将乐…