设计模式(二):创建型之工厂方法和抽象工厂模式

news2024/11/28 7:46:19

设计模式系列文章

设计模式(一):创建型之单例模式

设计模式(二):创建型之工厂模式


目录

  • 一、设计模式分类
  • 二、概述
  • 三、简单工厂模式
    • 1、结构
    • 2、实现
    • 3、扩展:静态工厂
  • 四、工厂方法模式
    • 1、结构
    • 2、 实现
    • 3、优缺点
  • 五、抽象工厂模式
    • 1、结构
    • 2、实现
    • 3、优缺点
  • 六、JDK源码解析-Collection.iterator方法


一、设计模式分类

  • 创建型模式
    • 用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”
    • 提供了单例、原型、工厂方法、抽象工厂、建造者 5 种创建型模式
  • 结构型模式
    • 用于描述如何将类或对象按某种布局组成更大的结构
    • 提供了代理、适配器、桥接、装饰、外观、享元、组合 7 种结构型模式
  • 行为型模式
    • 用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责
    • 提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器 11 种行为型模式

二、概述

需求:设计一个咖啡店点餐系统

  • 设计一个咖啡类(Coffee)
  • 并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】)
  • 再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能
  • 具体类的设计如下:

在这里插入图片描述

  • 这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重
  • 假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则
  • 如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦
  • 如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的
  • 所以说,工厂模式最大的优点就是:解耦

三、简单工厂模式

  • 简单工厂不属于23种经典设计模式之一
  • 简单工厂不是一种设计模式,反而比较像是一种编程习惯

1、结构

简单工厂包含如下角色:

  • 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品 :实现或者继承抽象产品的子类
  • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品

2、实现

现在使用简单工厂对上面案例进行改进,类图如下:

在这里插入图片描述
工厂类代码如下:

public class SimpleCoffeeFactory {
    public Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffee;
    }
}
  • 如果需要Coffee对象直接从SimpleCoffeeFactory工厂中获取即可
  • 这样也就解除了和Coffee实现类的耦合,同时又产生了新的耦合
    • CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合
    • 工厂对象和商品对象的耦合
  • 如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory的代码,违反了开闭原则

3、扩展:静态工厂

  • 在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的
  • 这个就是静态工厂模式,它也不是23种设计模式中的
  • 代码如下:
public class SimpleCoffeeFactory {
    public static Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffe;
    }
}

四、工厂方法模式

  • 针对上例中的缺点,使用工厂方法模式就可以完美的解决,完全遵循开闭原则
  • 定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象
  • 工厂方法使一个产品类的实例化延迟到其工厂的子类

1、结构

工厂方法模式的主要角色:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应

2、 实现

使用工厂方法模式对上例进行改进,类图如下:

在这里插入图片描述

抽象工厂:

public interface CoffeeFactory {
    Coffee createCoffee();
}

具体工厂:

public class LatteCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}

public class AmericanCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}

咖啡店类:

public class CoffeeStore {

    private CoffeeFactory factory;

    public CoffeeStore(CoffeeFactory factory) {
        this.factory = factory;
    }

    public Coffee orderCoffee(String type) {
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}
  • 要增加产品类时也要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点
  • 工厂方法模式是简单工厂模式的进一步抽象
  • 由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点

3、优缺点

优点

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程
  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则

缺点

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度

五、抽象工厂模式

  • 工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机

  • 工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品

  • 本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族

  • 下图所示横轴是产品等级,也就是同一类产品

  • 纵轴是产品族,也就是同一品牌的产品,同一品牌的产品产自同一个工厂
    在这里插入图片描述

    在这里插入图片描述

  • 抽象工厂模式是工厂方法模式的升级版本

  • 工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品

1、结构

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

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

2、实现

  • 现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点,如提拉米苏、抹茶慕斯等
  • 要是按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况
  • 拿铁咖啡和提拉米苏是同一产品族(也就是都属于意大利风味)
  • 美式咖啡和抹茶慕斯是同一产品族(也就是都属于美式风味)
  • 使用抽象工厂模式实现。类图如下:

在这里插入图片描述

抽象工厂:

public interface DessertFactory {

    //生产咖啡的功能
    Coffee createCoffee();

    //生产甜品的功能
    Dessert createDessert();
}

具体工厂:

//美式甜点工厂
public class AmericanDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }

    public Dessert createDessert() {
        return new MatchaMousse();
    }
}
//意大利风味甜点工厂
public class ItalyDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }

    public Dessert createDessert() {
        return new Tiramisu();
    }
}

客户端:

  • Coffee和Dessert是抽象产品类
  • show(),抽象类中定义行为,具体实现交给子类
public class Client {
    public static void main(String[] args) {
        //创建的是意大利风味甜品工厂对象
        //ItalyDessertFactory factory = new ItalyDessertFactory();
        AmericanDessertFactory factory = new AmericanDessertFactory();
        //获取拿铁咖啡和提拉米苏甜品
        Coffee coffee = factory.createCoffee();
        Dessert dessert = factory.createDessert();

        System.out.println(coffee.getName());
        dessert.show();
    }
}

如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类

3、优缺点

优点

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

缺点

  • 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改

六、JDK源码解析-Collection.iterator方法

public class Demo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("令狐冲");
        list.add("风清扬");
        list.add("任我行");

        //获取迭代器对象
        Iterator<String> it = list.iterator();
        //使用迭代器遍历
        while(it.hasNext()) {
            String ele = it.next();
            System.out.println(ele);
        }
    }
}
  • 对上面的代码大家应该很熟,使用迭代器遍历集合,获取集合中的元素
  • 而单列集合获取迭代器的方法就使用到了工厂方法模式
  • 通过类图看看结构

在这里插入图片描述

  • Collection接口是抽象工厂类(声明Iterator iterator()方法)
  • ArrayList是具体的工厂类(new Itr()创建返回Iterator对象)
  • Iterator接口是抽象商品类(Itr实现Iterator接口类)
  • ArrayList类中的Iter内部类是具体的商品(Itr是ArrayList内部类)
  • 在具体的工厂类中iterator()方法创建具体的商品类的对象

在这里插入图片描述

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

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

相关文章

牛客网2018吉比特校招技术开发类试题分析

最近做了两套笔试题&#xff0c;复习一下错题&#xff0c;有很多地方需要查缺补漏&#xff0c;再谈一下感受总结一下。 2018届吉比特校招技术类笔试B卷 吉比特2018届提前批校园招聘-开发类试卷 一、基础题 1.已知 a 6789x 6789、b 6789x 6790、c 6789x 6791&#xff0c…

GIT | 浅析原理篇

此篇文章主要是讲讲 一些 git 操作发生的时候 , .git 文件如何变化&#xff0c;git 背后发生了什么。磨刀不误砍柴工嘛&#xff01;算是一篇视频观后笔记&#xff08;文末取视频地址&#xff09; 基础概念 Git 是一个代码版本管控的工具&#xff0c;是一个内容寻址文件系统&am…

剑指 Offer 14- I. 剪绳子解题思路

文章目录 题目解题思路优化 题目 给你一根长度为 n 的绳子&#xff0c;请把绳子剪成整数长度的 m 段&#xff08;m、n都是整数&#xff0c;n>1并且m>1&#xff09;&#xff0c;每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少&…

Spring Boot + vue-element 开发个人博客项目实战教程(二十六、前端首页统计完善及完结)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 后端代码gitee地址&#xff1a;https://gitee.com/whxyh/personal_blog …

设计模式六大原则的理解

本文参考&#xff1a; 设计模式简介 | 菜鸟教程 (runoob.com) 六大设计原则之依赖倒置原则&#xff08;DIP&#xff09; - 简书 (jianshu.com) 设计模式的六大原则有&#xff1a; 1、开闭原则&#xff08;Open Close Principle&#xff09; 开闭原则的意思是&#xff1a;对扩…

设计模式之~桥接模式

桥接模式&#xff1a; 将抽象部分与它的实现部分分离&#xff0c;使他们都可以独立地变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦。 什么叫抽象与它的实现分离&#xff0c;这并不是说&#xff0c;…

图解系列 图解Spring Boot 最大连接数及最大并发数

文章目录 概序架构图TCP的3次握手4次挥手时序图核心参数AcceptCountMaxConnectionsMinSpareThread/MaxThreadMaxKeepAliveRequestsConnectionTimeoutKeepAliveTimeout 内部线程AcceptorPollerTomcatThreadPoolExecutor 测试参考 每个Spring Boot版本和内置容器不同&#xff0c;…

树状数组学习总结

今天本初中生蒟蒻学习了一下 树状数组 \color{red}{树状数组} 树状数组&#xff0c;总结一下~~~ 树状数组的实现 功能简介 快速求前缀和&#xff08; O ( l o g 2 n ) \color{purple}{O(log_2n)} O(log2​n)&#xff09;修改某一个数&#xff08; O ( l o g 2 n ) \color{gr…

SpringBoot+原生awt,实现花花绿绿的图形验证码

图形验证码是用于验证用户身份的一种方式&#xff0c;通常在网站注册、登录或进行某些敏感操作时会使用。它通过展示一个包含随机字符或数字的图形&#xff0c;要求用户输入相应的字符或数字来证明其为真人而非机器人。图形验证码能有效地防止机器人攻击和恶意注册行为&#xf…

Excel·VBA自动生成日记账的对方科目

如图&#xff1a;根据日记账/序时账的日期、凭证号为一组&#xff0c;按借贷方向生成相反的科目&#xff0c;并写入H列。可能存在一对一、一对多、多对多等情况的账目 目录 数组法遍历、判断、写入测试结果 多对多问题处理测试结果 数组法遍历、判断、写入 适用日期凭证号连续…

HTTPS的加密流程——巨详细!

文章目录 前言HTTPS的工作过程引入对称加密引入非对称加密引入证书完整的加密流程总结 前言 HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现一些被篡改的情况. 比如&#xff1a;臭…

民宿预订系统的设计与实现(ASP.NET,SQLServer)

这个民宿预订系统是由第三方的运营公司来运营&#xff0c;他提供了一个民宿和客户都使用的一个信息平台&#xff0c;民宿注册之后把自己的民宿信息发布到网站平台上&#xff0c;然后发布自己的房间信息&#xff0c;打折信息等供客户查看和选择。客户可以在网站平台上查看民宿信…

深度学习:大模型的正则化

l1l2正则和dropout正则化[https://youzipi.blog.csdn.net/article/details/75307522] LN和BN归一化 [深度学习:批归一化Batch Normalization] 主流大模型使用的Normalization主要有三类,分别是Layer Norm,RMS Norm,以及Deep Norm。 Post-Norm和Pre-Norm 根据Normalizat…

网工内推 | 快手、瑞芯微招运维,思科、红帽认证优先

01 快手 招聘岗位&#xff1a;IT系统运维 职责描述&#xff1a; 1、负责IT基础架构运维体系的建设和优化改进&#xff1b; 2、负责IT核心基础服务&#xff08;如DNS、负载均衡、容器&#xff09;的架构设计、平台建设和运维&#xff1b; 3、负责IT内部日志系统、监控系统、报警…

SpringCloud微服务框架(通俗易懂,一秒上手)

&#x1f381;&#x1f381;资源&#xff1a;https://pan.baidu.com/s/1zRmwSvSvoDkWh0-MynwERA&pwd1234 SpringCloud微服务框架 &#xff08;一&#xff09;认识微服务服务架构演变SpringCloud &#xff08;二&#xff09;微服务拆分案例服务拆分服务间调用 &#xff08;三…

ROS:订阅者Subscriber的编程实现(C++)

目录 一、话题模型二、创建功能包三、创建Subscriber代码四、编译代码五、运行 一、话题模型 图中&#xff0c;我们使用ROS Master管理节点。 有两个主要节点&#xff1a; Publisher&#xff0c;名为Turtle Velocity&#xff08;即海龟的速度&#xff09; Subscriber&#xff0…

Rocketmq面试(一) Rocketmq同一个消费组订阅不同的Tag,会有什么问题?

先说结果&#xff1a;会造成数据丢失 再说依据&#xff1a; RocketMQ要求同一个消费者组内的消费者必须订阅关系一致&#xff0c;如果订阅关系不一致会出现消息丢失的问题。 官网入口&#xff1a;订阅关系一致 | RocketMQ 不想看官网的&#xff0c;直接看结论 什么叫订阅关…

复杂SQL实践-MYSQL

MySQL 8.0窗口函数 MySQL从8.0版本开始支持窗口函数。 窗口函数总体上可以分为序号函数, 分布函数, 前后函数, 首尾函数和其他函数。 描述 题目&#xff1a;现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。 示例1 drop table if exist…

对远程http服务的拨测体验

背景&#xff1a; 过程是这样的&#xff0c;需要与合作方数据进行交互&#xff08;肯定是不允许直接连对方数据源的&#xff09;&#xff0c;对方提供了两台server&#xff0c;后端同事在server上面作了proxy搭建了桥接的应用&#xff08;两台server没有公网ip&#xff0c;通过…

Eclipse 教程Ⅹ

本次内容会涉及到Eclipse 重构菜单、Eclipse 添加书签和Eclipse 任务管理&#xff0c;老规矩&#xff0c;直接开始吧&#xff01; Eclipse 重构菜单 使用Eclipse重构 在项目开发中我们经常需要修改类名&#xff0c;但如果其他类依赖该类时&#xff0c;我们就需要花很多时间去…