设计模式——工厂三兄弟之工厂方法

news2024/11/16 6:47:54

1.业务需求

​ 大家好,我是菠菜啊。在介绍这期工厂方法模式前,我们先来看看这样的需求:升级之前的计算器,增加对数和指数运算。(看这篇文章前可以先回顾《设计模式——工厂三兄弟之简单工厂》这篇)
在这里插入图片描述
在这里插入图片描述

高級計算器

2.初步实现

实现初步思路:

​ 新增运算类的子类对数和指数运算类,修改OperationFactory类,增加创建对数和指数子类判断分支。
在这里插入图片描述

OperationFactory类:

public class OperationFactory {

    public static AOpeartion createOperation(String operator){
        AOpeartion opeartion=null;
        switch (operator){
            case "+":
                opeartion=new OperationAdd();
                break;
            case "-":
                opeartion=new OperationSub();
                break;
            case "*":
                opeartion=new OperationMul();
                break;
            case "/":
                opeartion=new OperationDiv();
                break;
            case "log":
                opeartion=new OperationLog();
                break;
            case "pow":
                opeartion=new OperationPow();
                break;
        }

        return opeartion;
    }
}

​ OperationLog类:

public class OperationLog extends AOpeartion {
    @Override
    public Double getOperationResult(double numbera, double numberb) {
        return Math.log(numbera)/Math.log(numberb);
    }
}

​ OperationPow类:

public class OperationPow extends AOpeartion {
    @Override
    public Double getOperationResult(double numbera, double numberb) {
        return Math.pow(numbera,numberb);
    }
}

思考:上述代码是按照上一篇简单工厂设计模式来设计的,每增加一种运算都要修改运算工厂类,影响了原有的代码运行,违反了开闭原则**。期望新增这俩种运算不影响现有程序,并且有扩展性。那么问题出现在哪里呢?我们发现OperationFactory不够抽象,应该针对接口编程,而不是实现编程(《设计模式基础——设计原则介绍》这篇的依赖倒置原则)。

3.方案改进

改造思路:

​ 新增抽象类AFactory,增加基础工厂类BasicOperationFactory、高级工厂类AdvanceOperationFactory子类,将之前的加减乘除运算子类对象的创建移动到BasicOperationFactory中,AdvanceOperationFactory中添加指数和对数运算子类对象的创建逻辑。增加OperationFactory2类,根据输入的运算符创建相应的工厂类,并且输出相应的运算子类。

在这里插入图片描述

AFactory类:

public abstract class AFactory {
    public abstract   AOpeartion createOperation(String operator);
}

BasicOperationFactory类:

public  class BasicOperationFactory extends AFactory {

    public    AOpeartion createOperation(String operator){
        AOpeartion opeartion=null;
        switch (operator){
            case "+":
                opeartion=new OperationAdd();
                break;
            case "-":
                opeartion=new OperationSub();
                break;
            case "*":
                opeartion=new OperationMul();
                break;
            case "/":
                opeartion=new OperationDiv();
                break;
            case "log":
                opeartion=new OperationLog();
                break;
            case "pow":
                opeartion=new OperationPow();
                break;
        }

        return opeartion;
    }
}

AdvanceOperationFactory类:

public  class AdvanceOperationFactory extends AFactory {

    public    AOpeartion createOperation(String operator){
        AOpeartion opeartion=null;
        switch (operator){
            case "log":
                opeartion=new OperationLog();
                break;
            case "pow":
                opeartion=new OperationPow();
                break;
        }

        return opeartion;
    }
}

OperationFactory2类:

public class OperationFactory2 {

    public static AOpeartion createOperation(String operator){
        AFactory factory=null;
        switch (operator){
            case "+":
            case "-":
            case "*":
            case "/":
                factory=new BasicOperationFactory();
                break;
            case "log":
            case "pow":
                factory=new AdvanceOperationFactory();
                break;
        }

        return factory.createOperation(operator);
    }
}

CalClient2类:

public class CalClient2 {
    public static void main(String[] args) {

        Scanner sc=new Scanner(System.in);
        System.out.println("请输入第一个数:");
        double numbera=sc.nextDouble();
        System.out.println("请输入运算符:");
        String operator=sc.next();
        System.out.println("请输入第二个数:");
        double numberb=sc.nextDouble();


        AOpeartion opeartion= OperationFactory2.createOperation(operator);
        if(null!=opeartion){
            System.out.println("运算结果为:"+(opeartion.getOperationResult(numbera,numberb)));
        }else{
            System.out.println("运算工厂获取运算类失败");

        }


    }
}

思考:OperationFactory工厂类通过输入的运算符去实例化相应合适的对象,通过多态返回父类的方式实现了计算器的结果。后续如果修改具体的计算方法只要修改具体的计算类即可,不会影响其它计算类。如果增加计算方法,增加实现相应的计算类的具体子类以及增加计算工厂类的switch分支即可。需求是变化的,而且我们不可能事先就了解所有的需求,所以我们在设计的时候就要考虑后续的可扩展性、可维护性

4.定义和组成结构

工厂方法模式(FactoryMethod),定义一个创建产品对象的工厂接口,让工厂子类决定实例化那一个产品类。工厂方法使一个类的实例化延迟到其子类

我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则

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

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

5.优缺点以及应用场景

优点:

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程,延续了简单工厂创建者和使用者的分离的优点
  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
  • 高层模块只需要知道产品的抽象类,解耦,满足迪米特法则

缺点:

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

适用场景:

  • 使用者只知道创建产品的工厂名,而不知道具体的产品名。
  • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。

友情提示:请尊重作者劳动成果,如需转载本博客文章请注明出处!谢谢合作!
【作者:我爱吃菠菜 个人博客地址

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

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

相关文章

Comfyui导出图片的命名技巧,日期文件夹

种子序号命名:%KSampler.seed% 图片宽高序号命名:%Empty Latent Image.width%x%Empty Latent Image.height% 年月日:%date:yyyy-MM-dd% 时分秒:%date:hhmmss% 年月日种子序号:%date:yyyy-MM-dd%/%KSampler.seed%

「清新题精讲」CF260E - Dividing Kingdom

CF260E - Dividing Kingdom D e s c r i p t i o n \mathrm{Description} Description 给定 n n n 个点 ( x i , y i ) (x_i,y_i) (xi​,yi​) 和长度为 9 9 9 的数列 a a a,满足 ∑ i 1 n a i n \sum_{i1}^na_in ∑i1n​ai​n。通过 2 2 2 条平行于 x x …

Mac连接虚拟机(Linux系统)

1.确定虚拟机的IP地址 ifconfig //终端命令,查询ip地址 sudo apt install net-tools 安装完成后再次执行 ifconfig: 2.安装SSH(加密远程登录协议) (1).安装OpenSSH服务器软件包: sudo apt-get install openssh-ser…

leetCode.86. 分隔链表

leetCode.86. 分隔链表 题目思路&#xff1a; 代码 class Solution { public:ListNode* partition(ListNode* head, int x) {auto lh new ListNode(-1), rh new ListNode(-1);auto lt lh, rt rh;for(auto p head; p; p p->next ) {if(p->val < x) {lt lt->…

33 mid 55. 跳跃游戏

贪心算法&#xff1a; class Solution {public boolean canJump(int[] nums) {int leftBorder 0;for (int i 0; i <nums.length; i) {if(i<leftBorder){leftBorderMath.max(leftBorder,inums[i]);}if(leftBorder>nums.length-1){return true;}}return false;} }

精酿啤酒:品质与口感对啤酒消费趋势的影响

随着消费市场的不断变化&#xff0c;啤酒消费趋势也在发生着演变。在这个过程中&#xff0c;品质与口感成为了影响啤酒消费趋势的重要因素。对于Fendi club啤酒而言&#xff0c;其卓着的品质和与众不同的口感对啤酒消费趋势产生了深远的影响。 品质的提升是推动啤酒消费趋势发展…

fastadmin部署后JSHint报错,导致Config::getValueByName()无法获取到值

问题 解决方案 一、本地 在phpstorm中&#xff0c;依次点击【设置】-【JSHint】-【取消勾选Enable】-【应用】即可。

Neural Filters:深度模糊

Ps菜单&#xff1a;滤镜/Neural Filters/摄影/深度模糊 Neural Filters/PHOTOGRAPHY/Depth Blur 深度模糊 Depth Blur滤镜可以在图像中创建环境深度以提供前景或背景对象。 “深度模糊”滤镜利用 AI 技术&#xff0c;分析图像的深度信息&#xff0c;生成一个深度图&#xff0c;…

爬虫案例-亚马逊反爬分析-验证码突破(x-amz-captcha)

总体概览&#xff1a;核心主要是需要突破该网站的验证码&#xff0c;成功后会返回我们需要的参数后再去请求一个中间页&#xff08;类似在后台注册一个session&#xff09;&#xff0c;最后需要注意一下 IP 是不能随意切换的 主要难点&#xff1a; 1、梳理整体反爬流程 2、验证…

【JavaScript】ECMAS6(ES6)新特性概览(二):解构赋值、扩展与收集、class类全面解析

&#x1f525; 个人主页&#xff1a;空白诗 &#x1f525; 热门专栏&#xff1a;【JavaScript】 文章目录 &#x1f33f; 引言五、 Destructuring Assignment - 解构赋值&#xff0c;数据提取的艺术 &#x1f3a8;&#x1f4cc; 数组解构&#x1f4cc; 对象解构&#x1f4cc; 特…

iOS自动连接已知Wi-Fi功能的实现

首先需要在配置文件申请的时候将hotspot勾选上&#xff0c;之后还要在x-code里添加对应的配置&#xff0c;由于我们并没有用到获取设备周边Wi-Fi的功能&#xff0c;所以就没申请相关权限 相关连接Wi-Fi代码如下&#xff1a; #import <NetworkExtension/NetworkExtension.h&…

LeetCode583:两个字符串的删除操作

题目描述 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 代码 解法1 /*dp[i][j]&#xff1a;以i-1为结尾的wrod1中有以j-1为尾的word2的个数为了让word1和word2相同&#xff0c;最少操作…

排序专题(常见8种)【思路解析和代码实现】【2w字长文】

排序专题&#xff08;常见8种&#xff09; 1.排序的概念及其运用 1.1排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中…

如何在文档中有效添加网格:技巧与实例

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;为何添加网格至关重要 二、网格添加的基本步骤 1. 确定网格类型和样式…

解决 Echarts 图 tooltip 层级太高穿透问题

问题场景&#xff1a;Echarts 图 tooltip 是自动轮播的&#xff0c;当点击某个区域出现弹窗时&#xff0c;tooltip和弹窗同时显示&#xff0c;没在遮罩层下面&#xff0c;查看tooltip的层级显示99999&#xff0c;所以这里改一下tooltip的层级。 设置 extraCssText: "z-ind…

vue3 使用vant

使用前提&#xff1a; vite创建的vue3项目 vanthttps://vant-ui.github.io/vant/#/zh-CN/home npm i vant 引入样式&#xff1a; main.js import vant/lib/index.css vant封装 import { showLoadingToast,closeToast,showDialog,showConfirmDialog } from vant;export func…

使用docker部署项目

一、docker私有镜像仓库 1、docker私有镜像仓库 库&#xff08;Repository&#xff09;是集中存放镜像的地方&#xff0c;又分为公共镜像和私有仓库。 当我们执行docker pull xxx的时候&#xff0c;它实际上是从registry.docker.com这个地址去查找&#xff0c;这就是Docker公…

计量和测量的区别有哪些?两者的关系是什么样的?

计量和测量在行业内经常被混用&#xff0c;更不用说外行人对计量和测量的定义不够清晰&#xff0c;无论是看字面还是定义&#xff0c;似乎两者没有什么太大的区别&#xff0c;但实际上&#xff0c;两者还是有区别的&#xff0c;不过又存在千丝万缕的联系&#xff0c;那么计量和…

【惊艳视界】Perfectly Clear Workbench:让您的图像瞬间焕发生机!

在数字化时代&#xff0c;图像已成为我们生活中不可或缺的一部分。无论是摄影爱好者&#xff0c;还是专业设计师&#xff0c;都渴望拥有一款能够轻松提升图像质量的神奇工具。今天&#xff0c;我们为您带来了一款图像清晰处理软件的佼佼者——Perfectly Clear Workbench&#x…

009-Linux的管道和重定向

文章目录 前言 一、重定向 1.1、FD简介 1.2、FD举例 1.3、重定向简介 1.3.1、输出重定向 正确输出&#xff1a; 错误输出 案例1&#xff1a;正确输出重定向 案例2&#xff1a;错误输出重定向 ​编辑 案例3&#xff1a;正确和错误都输出重定向到相同位置 1.3.2、输…