【Spring6】| GoF之工厂模式

news2024/11/15 17:25:21

目录

一:GoF之工厂模式

1. 工厂模式的三种形态

2. 简单工厂模式

3. 工厂方法模式

4.  抽象工厂模式(了解)


一:GoF之工厂模式

(1)GoF(Gang of Four),中文名——四人组。

(2)设计模式:一种可以被重复利用的解决方案。

(3)《Design Patterns: Elements of Reusable Object-Oriented Software》(即《设计模式》一书),1995年由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著。这几位作者常被称为"四人组(Gang of Four)"。

(4)该书中描述了23种设计模式,我们平常所说的设计模式就是指这23种设计模式;不过除了GoF23种设计模式之外,还有其它的设计模式,比如:JavaEE的设计模式(DAO模式、MVC模式等)!

GoF23种设计模式可分为三大类:

创建型(5个):解决对象创建问题

  • 单例模式
  • 原型模式
  • 建造者模式
  • 抽象工厂模式
  • 工厂方法模式

结构型(7个)一些类或对象组合在一起的经典结构

  • 代理模式
  • 桥接模式
  • 外观模式
  • 享元模式
  • 组合模式
  • 适配器模式
  • 装饰模式

行为型(11个):解决类或对象之间的交互问题

  • 策略模式
  • 解释器模式
  • 中介者模式
  • 访问者模式
  • 状态模式
  • 备忘录模式
  • 命令模式
  • 迭代子模式
  • 观察者模式
  • 责任链模式
  • 模板方法模式

1. 工厂模式的三种形态

(1)工厂模式是解决对象创建问题的,所以工厂模式属于创建型设计模式!这里为什么学习工厂模式呢?这是因为Spring框架底层使用了大量的工厂模式!

(2)工厂模式通常有三种形态:

  • 第一种:简单工厂模式(Simple Factory):不属于23种设计模式之一。简单工厂模式又叫做:静态工厂方法模式。简单工厂模式是工厂方法模式的一种特殊实现
  • 第二种:工厂方法模式(Factory Method):是23种设计模式之一。
  • 第三种:抽象工厂模式(Abstract Factory):是23种设计模式之一。

2. 简单工厂模式

(1)简单工厂模式是工厂方法模式的一种特殊实现,又被称为:静态工厂方法模式!

(2)简单工厂模式的角色包括三个:

  • 抽象产品 角色
  • 具体产品 角色
  • 工厂类 角色

抽象产品 角色

Weapon武器类

package com.bjpowernode.simple.factory;

// 抽象产品角色
public abstract class Weapon {

    // 所有的武器都可以攻击。 
    public abstract void attack();
}

具体产品 角色

Tank坦克类

package com.bjpowernode.simple.factory;

// 具体产品角色
public class Tank extends Weapon{
    @Override
    public void attack() {
        System.out.println("坦克开炮!!!");
    }
}

 Fighter战斗机类

package com.bjpowernode.simple.factory;

// 具体产品角色
public class Fighter extends Weapon{
    @Override
    public void attack() {
        System.out.println("战斗机抛下小男孩!!!!");
    }
}

 Dagger匕首类

package com.bjpowernode.simple.factory;

// 具体产品角色
public class Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("砍丫的!!!");
    }
}

工厂类 角色 

WeaponFactory武器工厂类

①是静态方法,要获取什么产品?就看你传什么参数,传TANK获取坦克,传DAGGER获取匕首,传FIGHTER获取战斗机
简单工厂模式中有一个静态方法,所以被称为:静态工厂方法模式

package com.bjpowernode.simple.factory;

// 工厂类角色
public class WeaponFactory {
    public static Weapon get(String weaponType){

        if ("TANK".equals(weaponType)) {
            return new Tank();
        } else if ("DAGGER".equals(weaponType)) {
            return new Dagger();
        } else if ("FIGHTER".equals(weaponType)) {
            return new Fighter();
        } else {
            throw new RuntimeException("不支持该武器的生产");
        }
    }

}

客户端程序---进行测试 

①对于客户端来说,坦克的生产细节(创建对象),并不需要关心,只需要向工厂索要即可!
简单工厂模式达到了什么呢?

职责分离,客户端不需要关心产品的生产细节;客户端只负责消费,工厂类负责生产;一个负责生产,一个负责消费;生产者和消费者分离了,这就是简单工厂模式的作用

package com.bjpowernode.simple.factory;

// 这是客户端程序
public class Test {
    public static void main(String[] args) {

        // 需要坦克
        Weapon tank = WeaponFactory.get("TANK");
        tank.attack();
        // 需要匕首
        Weapon dagger = WeaponFactory.get("DAGGER");
        dagger.attack();
        // 需要战斗机
        Weapon fighter = WeaponFactory.get("FIGHTER");
        fighter.attack();
    }
}

总结:Spring中的BeanFactory就使用了简单工厂模式!

(1)简单工厂模式解决什么问题(优点)呢?
客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责“消费”,工厂负责“生产”;生产和消费分离!

(2)简单工厂模式的缺点?
①假设现在需要扩展一个新的武器产品,WeaponFactory工厂类的代码是需要修改的,显然违背了OCP原则
②工厂类的责任比较重大,不能出现任何问题,因为这个工厂类负责所有产品的生产,称为全能类,或者叫做上帝类。这个工厂类一旦出问题,整个系统必然全部瘫痪!

3. 工厂方法模式

(1)工厂方法模式可以解决简单工厂模式当中的OCP问题。怎么解决的?一个工厂对应生产一种产品;这样工厂就不是全能类了,不是上帝类了;另外,也可以符合OCP原则。

(2)工厂方法模式的角色包括四个:

  • 抽象产品 角色
  • 具体产品 角色
  • 抽象工厂 角色
  • 具体工厂 角色

抽象工厂 角色

package com.bjpowernode.factory.method;

public abstract  class WeaponFactory {

    // 这个方法不是静态的,是实例方法。
    public abstract Weapon get();

}

具体工厂 角色---继承抽象工厂,一个工厂对应生产一种产品

DaggerFactory生产匕首的专有工厂

package com.bjpowernode.factory.method;

// 具体工厂角色
public class DaggerFactory extends WeaponFactory{
    @Override
    public Weapon get() {
        return new Dagger();
    }
}

TankFactory生产坦克的专有工厂

package com.bjpowernode.factory.method;

// 具体工厂角色
public class TankFactory extends WeaponFactory{
    @Override
    public Weapon get() {
        return new Tank();
    }
}
 

客户端程序---进行测试 

注:这里还是创建对象了,所以我们使用上面的简单工厂模式在抽象出一个大工厂,来管理创建对象的问题!这里暂时只考虑结局OCP的问题!

package com.bjpowernode.factory.method;

// 客户端程序
public class Test {
    public static void main(String[] args) {
        WeaponFactory weaponFactory = new DaggerFactory();
        Weapon dagger = weaponFactory.get();
        dagger.attack();

        WeaponFactory weaponFactory1 = new TankFactory();
        Weapon gun = weaponFactory1.get();
        gun.attack();
    }
}

总结:

(1)工厂方法模式的缺点:
每次增加一个产品时,都需要增加一个具体类对象实现工厂类,使得系统中类的个数成倍增加(存在类爆炸问题),在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖!

(2)工厂方法模式的优点:
①当你扩展一个产品的时候,符合OCP原则(扩展性高),因为只需要添加两个类,一个类是具体产品类,一个类是具体工厂类,都是添加类,没有修改之前的代码,所以符合OCP!
②一个调用者想创建一个对象,只要知道其名称就可以了,屏蔽产品的具体实现,调用者只关心产品的接口。

4.  抽象工厂模式(了解)

(1)Spring底层并没有调用抽象工厂模式,所以这部分可以暂时为了解!

(2)抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类!

(3)抽象工厂模式特点:

①抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。

②抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。

③抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。

④它有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类的实例。

⑤每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结果。

(4)抽象工厂中包含4个角色:

  • 抽象产品角色
  • 具体产品角色
  • 抽象工厂角色
  • 具体工厂角色

第一部分:武器产品

Weapon类武器产品族

package com.powernode.product;

// 武器产品族
public abstract class Weapon {
    // 所有武器都可以攻击
    public abstract void attack();
}

Gun类武器产品族中的产品等级1 

package com.powernode.product;

// 武器产品族中的产品等级1
public class Gun extends Weapon{
    @Override
    public void attack() {
        System.out.println("开枪射击!");
    }
}

Dagger类武器产品族中的产品等级2

package com.powernode.product;

// 武器产品族中的产品等级2
public class Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("砍丫的!");
    }
}

第二部分:水果产品

Fruit类水果产品族

package com.powernode.product;

// 水果产品族
public abstract class Fruit {
    // 所有果实都有一个成熟周期。 
    public abstract void ripeCycle();
}

Orange类水果产品族中的产品等级1

package com.powernode.product;

// 水果产品族中的产品等级1
public class Orange extends Fruit{
    @Override
    public void ripeCycle() {
        System.out.println("橘子的成熟周期是10个月");
    }
}

 Apple类水果产品族中的产品等级2

package com.powernode.product;

// 水果产品族中的产品等级2
public class Apple extends Fruit{
    @Override
    public void ripeCycle() {
        System.out.println("苹果的成熟周期是8个月");
    }
}

第三部分:抽象工厂类

package com.powernode.factory;

import com.powernode.product.Fruit;
import com.powernode.product.Weapon;

// 抽象工厂
public abstract class AbstractFactory {
    // 两个实例方法
    public abstract Weapon getWeapon(String type);
    public abstract Fruit getFruit(String type);
}

第四部分:具体工厂类

武器族工厂

package com.powernode.factory;

import com.powernode.product.Dagger;
import com.powernode.product.Fruit;
import com.powernode.product.Gun;
import com.powernode.product.Weapon;

// 武器族工厂
public class WeaponFactory extends AbstractFactory{

    public Weapon getWeapon(String type){
        if (type == null || type.trim().length() == 0) {
            return null;
        }
        if ("Gun".equals(type)) {
            return new Gun();
        } else if ("Dagger".equals(type)) {
            return new Dagger();
        } else {
            throw new RuntimeException("无法生产该武器");
        }
    }

    @Override
    public Fruit getFruit(String type) {
        return null;
    }
}

水果族工厂

package com.powernode.factory;

import com.powernode.product.*;

// 水果族工厂
public class FruitFactory extends AbstractFactory{
    @Override
    public Weapon getWeapon(String type) {
        return null;
    }

    public Fruit getFruit(String type){
        if (type == null || type.trim().length() == 0) {
            return null;
        }
        if ("Orange".equals(type)) {
            return new Orange();
        } else if ("Apple".equals(type)) {
            return new Apple();
        } else {
            throw new RuntimeException("果园不产这种水果");
        }
    }
}

第五部分:客户端程序 

package com.powernode.client;

import com.powernode.factory.AbstractFactory;
import com.powernode.factory.FruitFactory;
import com.powernode.factory.WeaponFactory;
import com.powernode.product.Fruit;
import com.powernode.product.Weapon;

public class Client {
    public static void main(String[] args) {
        // 客户端调用方法时只面向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.ripeCycle();
        apple.ripeCycle();
    }
}

总结

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

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

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

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

相关文章

前端开发总结的一些技巧和实用方法(2)

本文主要介绍一些JS中用到的小技巧和实用方法,可以在日常Coding中提升幸福度,也可以通过一些小细节来增加代码可读性,让代码看起来更加优雅,后续将不断更新1.数组 map 的方法 (不使用Array.Map) Array.from 还可以接受第二个参数…

一文讲解JDK自带监控工具查看 JVM 情况

在一文带你了解阿里的开源Java诊断工具 :Arthas_出世&入世的博客-CSDN博客这篇文章中介绍了Arthas的强大功能,但是有些生成环境没有安装,所以还是需要会使用JDK 自带监控JVM的工具。 常用的JDK 自带监控工具如下: jps&#x…

CDH大数据平台入门篇之搭建与部署

一、CDH介绍 1.CDH 是一个强大的商业版数据中心管理工具 提供了各种能够快速稳定运行的数据计算框架,如Spark; 使用Apache Impala做为对HDFS、HBase的高性能SQL查询引擎; 使用Hive数据仓库工具帮助用户分析数据; 提供CM安装HBas…

真正的IT技术男是什么样的?

我们经常会听到很多对IT男士的调侃称呼,“屌丝”、“宅男”,会逗的大家捧腹大笑。但是,大家要不要以为称呼IT男是“屌丝”、“宅男”,就当真以为他们是这样了。今天,青鸟学姐就带大家一起来了解一下,真正的…

代码还原小试牛刀(一):魔改的MD5

一、目标 2023年了,MD5已经是最基础的签名算法了,但如果你还只是对输入做了简单的MD5,肯定会被同行们嘲笑。加点盐(salt)是一种基本的提升,但在这个就业形势严峻的时代,仅仅加盐肯定不够了。 …

原腾讯QQ空间负责人,T13专家,黄希彤被爆近期被裁员,裁员原因令人唏嘘。。...

点击上方“码农突围”,马上关注这里是码农充电第一站,回复“666”,获取一份专属大礼包真爱,请设置“星标”或点个“在看这是【码农突围】的第 431 篇原创分享作者 l 突围的鱼来源 l 码农突围(ID:smartyuge&…

【论文速递】WACV 2023 - 一种全卷积Transformer的医学影响分割模型

【论文速递】WACV 2023 - 一种全卷积Transformer的医学影响分割模型 【论文原文】:The Fully Convolutional Transformer for Medical Image Segmentation 【作者信息】:Athanasios Tragakis, Chaitanya Kaul,Roderick Murray-Smith,Dirk Husmeier 论…

app上架专用软著认证电子版权在主流应用商店的使用说明2023年最新版

软著认证电子版权在主流应用商店的使用说明 目录 一、 华为应用商店 二、 腾讯应用宝 三、 小米开放平台 小米应用提交: 小米游戏提交: 四、 OPPO开放平台 OPPO应用提交: OPPO游戏(App)提交: OPPO小游戏(快应…

Python爬虫之用Selenium做爬虫

我们在用python做爬虫的时候,除了直接用requests的架构,还有Scrapy、Selenium等方式可以使用,那么今天我们就来聊一聊使用Selenium如何实现爬虫。 Selenium是什么? Selenium是一个浏览器自动化测试框架,是一款用于We…

2022年数维杯国际大学生数学建模挑战赛B题红VS蓝求解论文及程序

2022年数维杯国际大学生数学建模挑战赛 B题 红VS蓝 原题再现: 在现代战争中,攻守双方都需要引入有效的战争策略,以增加战争威胁并减少损失。只有形成相对稳定、平衡的战争态势,才能尽快实现达成共识的最终目标。 鉴于上述战争问…

代码随想录算法训练营第十七天 | 110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

打卡第17天,补卡中,懒狗又歇了几天。 今日任务 110.平衡二叉树257.二叉树的所有路径404.左叶子之和 110.平衡二叉树 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个…

(全网最详细)Mysql下载安装和配置方法(看了必成功)

Mysql下载 MySQL官网下载地址:MySQL 点击进行下载 解压到你想要安装的目录 新建my.ini文件复制以下内容粘贴进去修改basedir安装的目录,datadir安装的目录\data [mysqld] #设置3306端口 port3306 #设置mysql的安装目录 basedir #设置mysql数据库的数据…

KubeSphere 社区双周报 | OpenFunction v1.0.0-rc.0 发布

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为:2023.02.17-2023.…

idea插件推荐

idea插件推荐代码辅助GitHub CopilotAlibaba Cloud AI Coding AssistantTabnine AI Code Completion- JS Java Python TS Rust Go PHP & MoreiCodeJFormDesigner :图形用户界面生成器开发插件Mybatis HelperMaven HelperJPA Supportjava插件ptgGsonFormatPlusFastHotSwappe…

kibana查看日志

一、背景 kibana收集日志功能很强大,之前只是简单的使用,此次系统学习了解并分享一波 二、kibana查看日志的基本使用 1.选择查询的服务和日志文件 注意:每个应用配置了开发与生产环境,需要找到指定的应用 1.1选择对应的应用 1.…

wxpython设计GUI:wxFormBuilder工具常用布局结构介绍之布局四—面板拼接式

python借助wxFormBuilder工具搭建基础的GUI界面—wxFormBuilder工具使用介绍:https://blog.csdn.net/Logintern09/article/details/126685315 布局四:面板拼接式,先Panel面板构图,再使用程序代码在Frame框架上拼接面板 下面讲一下…

SurfaceFlinger模块

SurfaceFlinger是一个系统服务,作用就是接受不同layer的buffer数据进行合成,然后发送到显示设备进行显示。SurfaceFlinger进程是什么时候起来的?在之前的Android低版本手机上,SurfaceFlinger进程是在init.rc中启动的,在…

.Net Core WebApi 在Linux系统Deepin上部署Nginx并使用(一)

前言: Deepin最初是基于Ubuntu的发行版 2015年脱离Ubuntu开发,开始基于Ubuntu上游Debian操作系统 2019年脱离Debian,直接基于Linux开发,真正属于自己的上游Linux系统发行版 2022年8月,新版《Deepin V23》我下载开始了我…

Registry与DGC的攻击利用

0x01 2022-02-03写的一篇文章。 0x02 Registry Registry指的是RMI的注册表,攻击的目标是注册表所在的机器,一般注册表和RMI Server在同一个机器上,特殊情况下也会在不同机器上。 在我们通过LocateRegistry#getRegistry获取到目标开启的注…

Win32:C++其实早已支持中文编程

我们以前学习C/C的时候,对于变量和标识符的命名都有如下规则: 变量名必须由字母、数字、下划线构成只能以字母、下划线开头 似乎对中文不太友善啊,于是后来出现了一些中文编程的呼声,甚至还真的出现了一些中文编程语言。 其实在…