Java中使用工厂模式和策略模式优雅消除if-else语句(UML类图+案例分析)

news2024/11/29 22:52:29

 前言:在最近的后端开发中,多多少少会发现有很多if-else语句,如果条件过多则会造成整体代码看起来非常臃肿,这边我就举一个我在实际开发中的例子,来进行阐述这两种模式在实际开发中我是如何运用的。

目录

一、工厂模式简介

二、简单工厂模式

2.1、UML类图

2.2、角色设计

2.3、代码实现

2.4、总结

三、工厂方法模式

3.1、UML类图

3.2、角色设计 

3.2、代码实现

3.3、总结

四、抽象工厂模式

4.1、UML类图

4.2、角色设计 

4.3、代码实现

4.4、总结

五、策略模式

5.1、UML类图

5.2、角色设计

5.3、代码实现

5.4、总结

六、使用工厂模式+策略模式消除if-else语句

一、SpringBoot项目(推荐)

二、普通的Java项目 

七、总结


一、工厂模式简介

工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,具体可以分为三种来进行逐一介绍,分别是简单工厂模式、工厂方法模式以及抽象工厂模式。这种模式可以使得我们代码的整体结构更加信息,有效的动态进行封装以及降低代码之间的耦合度。

二、简单工厂模式

2.1、UML类图

2.2、角色设计

角色描述
简单工厂负责创建所有实体类的内部逻辑,工厂类创建产品的方法可以直接被外部调用,以此来创建所修要的产品对象
抽象水果简单工厂模式创建对象的公用接口
具体水果公用接口创建的具体对象

2.3、代码实现

1、自定义一个水果接口

public interface Fruit {

    public void name();

}

2、自定义水果类-苹果

public class Apple implements Fruit{

    @Override
    public void name() {
        System.out.println("苹果");
    }

}

3、自定义水果类-西瓜

public class Watermelon implements Fruit{

    @Override
    public void name() {
        System.out.println("西瓜");
    }

}

4、创建一个简单的水果工厂,通过传递进来的水果名词进行生产水果

public class FruitFactory {

    public static Fruit makeFruit(String name){
        if("苹果".equals(name)){
            return new Apple();
        }else if ("西瓜".equals(name)){
            return new Watermelon();
        }else {
            return null;
        }
    }
    
}

5、市场类

public class Market {
    public static void main(String[] args) {
        Fruit fruit = FruitFactory.makeFruit("西瓜");
        fruit.name();
    }
}

2.4、总结

优点:简单工厂模式封装了创建对象的逻辑,完成了创建对象逻辑和业务代码之间的解耦。

缺点:每个具体的水果类的接口增多时,会需要在简单工程类中新增大批的对象生产的方法,这样在抽象工厂当中会有很多的if-else语句,同时也违背了“对修改关闭,对扩展开启的”原则(开闭原则)

三、工厂方法模式

3.1、UML类图

3.2、角色设计 

角色描述
抽象水果工厂定义了创建水果的方法,任何模式中在创建水果的工厂类必须实现这个接口
具体水果工厂实现抽象水果工厂接口的具体水果工厂类,负责生产具体的水果产品
抽象水果水果对象公用的接口
具体水果实现了抽象水果定义的接口,某具体的水果由某具体的工厂进行创建

3.2、代码实现

1、定义水果工厂接口

public interface FruitFactory {

    Fruit makeFruit();
    
}

2、定义水果接口

public interface Fruit {

    public void name();
    
}

3、自定义苹果实现类

public class Apple implements Fruit{

    @Override
    public void name() {
        System.out.println("苹果");
    }

}

4、自定义西瓜实现类

public class Watermelon implements Fruit{

    @Override
    public void name() {
        System.out.println("西瓜");
    }
    
}

5、自定义苹果生产工厂

public class AppleFactory implements FruitFactory{

    @Override
    public Fruit makeFruit() {
        return new Apple();
    }
    
}

6、自定义西瓜生产工厂

public class WatermelonFactory implements FruitFactory{

    @Override
    public Fruit makeFruit() {
        return new Watermelon();
    }

}

7、市场类

public class Market {
    
    public static void main(String[] args) {
        AppleFactory appleFactory = new AppleFactory();
        appleFactory.makeFruit().name();
    }
    
}

3.3、总结

优点:在简单工厂模式的基础上进行优化,完美符合了“开闭原则”和“单一职责原则”,便于进行扩展。

缺点:类的个数容易过多,增加代码的复杂度并且抽象工厂接口的具体工厂只可以生产单独一个类型的产品。

四、抽象工厂模式

4.1、UML类图

4.2、角色设计 

角色描述
抽象工厂声明生产水果的一个工厂接口(可以声明生产多个类型产品的方法)
具体工厂实现生产水果的具体实体类
抽象水果水果对象公用的接口
具体水果实现了抽象水果定义的接口,某具体的水果由某具体的工厂进行创建

4.3、代码实现

1、定义水果和包装接口

public interface Fruit {

    public void name();

}

public interface Package {

    public void name();

}

2、定义水果工厂接口

public interface FruitFactory {

    Fruit makeFruit();

    Package makePackage();

}

3、 定义苹果实现类以及对应的苹果包装实现类

public class Apple implements Fruit {

    @Override
    public void name() {
        System.out.println("苹果");
    }

}

public class ApplePackage implements Package{
    
    @Override
    public void name() {
        System.out.println("苹果包装");
    }
    
}

4、 定义西瓜实现类以及对应的西瓜包装实现类

public class Watermelon implements Fruit {

    @Override
    public void name() {
        System.out.println("西瓜");
    }

}

public class WatermelonPackage implements Package{

    @Override
    public void name() {
        System.out.println("西瓜包装");
    }
    
}

5、 自定义苹果工厂

public class AppleFactory implements FruitFactory {

    @Override
    public Fruit makeFruit() {
        return new Apple();
    }

    @Override
    public Package makePackage() {
        return new ApplePackage();
    }

}

6、自定义西瓜工厂

public class WatermelonFactory implements FruitFactory {

    @Override
    public Fruit makeFruit() {
        return new Watermelon();
    }

    @Override
    public Package makePackage() {
        return new WatermelonPackage();
    }

}

7、市场类

public class Market {

    public static void main(String[] args) {
        FruitFactory appleFactory = new AppleFactory();
        FruitFactory watermelonFactory = new WatermelonFactory();

        appleFactory.makeFruit().name();
        appleFactory.makePackage().name();

        watermelonFactory.makeFruit().name();
        watermelonFactory.makePackage().name();
    }

}

4.4、总结

优点:抽象工厂模式在工厂方法模式进行了进一步延伸,都是符合“开闭原则”,但是与工厂方法模式不同的是,工厂方法模式在新增一个具体的产品时候会需要增加对应的工厂,但是抽象工厂模式只有在新增一个系列的具体产品才需要新增工厂,就是说工厂方法模式只可以创建一个单一的具体产品,而抽象工厂模式可以创建多个且属于一个类型的具体产品。

缺点:产品族扩展比较繁琐,当新增一个系列的某一个产品时,需要增加具体的产品类,还需要增加对应的工厂类。

五、策略模式

策略模式是一种行为型模式,它将对象和行为拆开,将具体的行为定义为一个行为接口和具体的实现,把它们一个个封装起来,并且可以使他们互相替换。

5.1、UML类图

5.2、角色设计

角色描述
策略抽象接口用于定义若个算法的表示
具体策略类是策略抽象接口的具体实现,说白了就是重写策略的方法
策略上下文类上下文包含用策略(接口)声明的变量,委托策略变量调用具体策略所实现的策略接口中的方法(

5.3、代码实现

1、定义支付策略接口

public interface PayStrategy {

    void pay();

}

2、微信支付策略实现类

public class WXStrategy implements PayStrategy{

    @Override
    public void pay() {
        System.out.println("微信支付");
    }

}

3、支付宝策略实现类

public class ZFBStrategy implements PayStrategy{

    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }

}

4、策略上下文实现

public class StrategyContext {

    private PayStrategy payStrategy;

    public StrategyContext(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    public void pay(){
        this.payStrategy.pay();
    }

}

5、主方法测试 

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

        PayStrategy wx = new WXStrategy();
        PayStrategy zfb = new ZFBStrategy();

        StrategyContext wxContext = new StrategyContext(wx);
        StrategyContext zfbContext = new StrategyContext(zfb);

        wxContext.pay();
        zfbContext.pay();

    }
}

5.4、总结

优点:策略模式完全符合了“开闭原则”,用户可以在不修改原有系统基础的选择上,可以灵活的切换对应的行为,同时也提供了管理相关的算法族的方法和替换集成关系的方法,最后也避免了多重的条件语句。

缺点:策略模式会产生很多的策略类,客户端必须要知道所有的策略类来自我决定要使用哪一种策略。

六、使用工厂模式+策略模式消除if-else语句

这边例如有一个需求:后端需要接收前端传递过来的修改的字段类型和修改具体内容去修改某个指定的字段,这边列举了两个例子,需要修改一个人的姓名或者是住址,如果是用传统的if-else语句是这样写的.

        String bulkType = "address";
        String bulkStr = "上海";
        if("name".equals(bulkType)){
            System.out.println("修改姓名为:" + bulkStr);
        } else if ("address".equals(bulkType)) {
            System.out.println("修改住址为:"+ bulkStr);
        }

如果修改的类型有5个甚至更多,那就会有很多冗余的if-else语句,这样就会显得整体代码不够优雅,非常臃肿,所以这边就需要我们用到java的设计模式去优化掉这段if-else语句。

一、SpringBoot项目(推荐)

1、策略接口

package com.example.strategic.service;

public interface Revise {

   public void execute(String str);

}

2、姓名修改策略类:

需要打上@Component注解交给Spring容器去管理并标识唯一的Bean名称。

package com.example.strategic.service;

import org.springframework.stereotype.Component;

@Component("name")
public class ReviseName implements Revise{
    @Override
    public void execute(String str) {
        System.out.println("修改姓名为:" + str);
    }
}

3、地址修改策略类:

package com.example.strategic.service;

import org.springframework.stereotype.Component;

@Component("address")
public class ReviseAddress implements Revise{

    @Override
    public void execute(String str) {
        System.out.println("修改住址为:"+str);
    }

}

4、策略工厂类

通过@Autowired按类型自动注入一个Map,Spring会自动将这些Bean根据其name作为键,实例作为值,注入到reviseMap这个Map中。

getReviseStrategy方法根据传入的bulkType参数作为键,从reviseMap中获取对应的Revise实现类实例。

调用者只需要传入bulkType即可,不需要关心具体实现类,实现了面向接口编程。

package com.example.strategic.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class ReviseFactory {

    @Autowired
    private Map<String,Revise> reviseMap;

    public Revise getReviseStrategy(String bulkType) throws Exception {
        Revise reviseStrategy = reviseMap.get(bulkType);
        if(reviseStrategy == null){
            throw new Exception("错误的选项!");
        }
       return reviseStrategy;
    }

}

5、测试运行

@SpringBootTest
class StrategicApplicationTests {

    @Resource
    ReviseFactory bulkFactory;

    @Test
    void contextLoads() throws Exception {
        Revise revise = bulkFactory.getReviseStrategy("address");
        revise.execute("上海");
    }

}

6、运行结果 

二、普通的Java项目 

1、策略接口

public interface Revise {

   public void execute(String str);

}

2、姓名修改策略类

public class ReviseName implements Revise{
    @Override
    public void execute(String str) {
        System.out.println("修改姓名为:" + str);
    }
}

3、地址修改策略类

public class ReviseAddress implements Revise{

    @Override
    public void execute(String str) {
        System.out.println("修改住址为:"+str);
    }

}

4、策略工厂类

public class ReviseFactory {

    private static Map<String, Revise> map = new HashMap<>();

    static {
        map.put("name", new ReviseName());
        map.put("address", new ReviseAddress());
    }

    public static Revise getReviseStrategy(String str) {
        return map.get(str);
    }
    
}

5、测试运行

    public static void main(String[] args) {
        String bulkType = "address";
        String bulkStr = "上海";
        //获取对应的策略接口
        Revise revise = ReviseFactory.getReviseStrategy(bulkType);
        // 调用具体策略方法
        revise.execute(bulkStr);
    }

6、运行结果

七、总结

本篇博客汇总了我对工厂模式和策略模式的理解,以及我是如何把它们巧妙运用在实际项目当中的一些技巧进行了分享,如有问题,欢迎评论区讨论!

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

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

相关文章

Web APls-day05

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; Window对象 BOM BOM(Browser Object Model ) 是浏览器对象模型 window对象是一个全局对象&#xff0c;也可以说是…

❤️创意网页:猜数字游戏

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

【架构设计】高并发架构实战:从需求分析到系统设计

写在前面 很多软件工程师的职业规划是成为架构师&#xff0c;但是要成为架构师很多时候要求先有架构设计经验&#xff0c;而不做架构师又怎么会有架构设计经验呢&#xff1f;那么要如何获得架构设计经验呢&#xff1f; 1 高并发是什么 高并发是指系统在同一时间内处理的请求量…

左神算法中级提升(3)

目录 【案例1】 【题目描述】【2018阿里巴巴面试题】 【思路解析】 【代码实现】 【案例2】 【题目描述】 【思路解析1】 【思路解析2】 【代码实现】 【案例3】 【题目描述】 【思路解析】 【代码实现】 【案例4】 【题目描述】 【思路解析】 【代码实现】 【案例5】…

无人机禁飞区地图更新!图新地球全国限飞区自定义地图免费分享!

随着无人机的普及&#xff0c;人们越来越容易拥有一台无人机。但很多用户并不了解无人机的飞行规则和禁飞限制。对于没有严格遵守规定的人来说&#xff0c;无人机飞行往往会构成公共安全和私人财产的潜在危害。 为此&#xff0c;政府和航空管理机构陆续出台了一系列限制无人机…

247个Python练习案例附源码(百看不如一练)

众所周知&#xff0c;我们在学习Pyhont过程中&#xff0c;大都看书枯燥、看视频进度慢&#xff0c;网上查找的学习案例又比较凌乱不成体系。。。 百看不如一练&#xff0c;今天为大家搜集了一份Python从入门到进阶的实战案例合集&#xff0c;共计247个案例&#xff0c;185页内…

【数据仓库】BI看板DataEase入坑指南

开头夸夸国产开源BI软件DataEase&#xff0c;支持常见各种报表&#xff0c;还支持图表联动和上下级钻取&#xff0c;超赞有木有&#xff01;&#xff01;&#xff01; 再来为什么说入坑&#xff0c;源码启动各种不服啊。本地用的maven3.5一直导入不了Java项目backend。后来看了…

【Linux后端服务器开发】缓冲区

目录 一、缓冲区概述 二、语言层面缓冲区 三、C语言模拟实现stdio库 一、缓冲区概述 Linux缓冲区是指在内存中开辟的一块区域&#xff0c;用于存储输入输出数据的临时存储区域。 当应用程序向文件或设备进行读写操作时&#xff0c;数据会先被存储到缓冲区中&#xff0c;然…

MYSQL学习第一天

1.创建数据库&#xff0c;删除数据库&#xff0c;查询创建数据的语句&#xff0c;使用数据库&#xff0c;查询当前默认的数据库以及使用的编码方式校验规则 1.1 创建数据库 create database db_name; 1.2 使用数据库 use db_name; 1.3 查询当前使用的数据库 select datab…

学校公寓管理系统

学校公寓管理系统是学校管理的重要组成部分&#xff0c;它的主要任务是通过数字化和自动化的方式提高公寓管理的效率&#xff0c;同时为学生提供更优质的服务。这个系统能够处理学生住宿的申请、房间的分配、住宿费用的收取以及公寓设施的使用等各项工作。 首先&#xff0c;学校…

【MR设备】燧光MR设备极简教程(使用篇)

燧光MR设备极简教程(使用篇) 一、硬件的基础使用二、定位信标三、投屏直播1、第三人称视角同步MR2、第一人称视角无线投屏相关文章:燧光MR设备极简教程(开发篇) 一、硬件的基础使用 官方使用文档:https://developer.ximmerse.com/#/example?id=6 1. 开机: 长按Home…

漫谈大数据时代的个人信息安全(一)——“按图索骥”

大数据时代的个人信息安全系列——“按图索骥” 一、寻找王珞丹二、啥是Exif &#xff1f;三、个人信息保护小贴士 近日&#xff0c;某高校毕业生在校期间窃取学校内网数据&#xff0c;收集全校学生个人隐私信息的新闻引发了人们对大数据时代个人信息安全问题的再度关注。在大数…

今日教会你录播课实时翻译怎么弄

在数字时代的浪潮中&#xff0c;视频教学是一种重要的教学方式。无论在网络教学平台&#xff0c;还是在大学教育或公司的培训中&#xff0c;录制课程都以其灵活、方便的特点&#xff0c;给广大师生提供了极大的便利。但是&#xff0c;随着国际间交往的不断深入&#xff0c;语言…

【第七章】习题

1、 下列代码创建了几个对象 public class stringPool {public static void main(String[] args) {String s1 new String("abc");String s2 new String("abc");if (s1 s2) {System.out.println("在堆中只创建了一个对象");} else {System.out…

(vue)整个页面添加背景视频

(vue)整个页面添加背景视频 App.vue <template><div id"app" :class"[platform]"><video src"./assets/images/top/bg-video-711.mp4" autoplay muted loop class"bg"></video><router-view /></di…

智能优化算法——灰狼优化算法(PythonMatlab实现)

目录 1 灰狼优化算法基本思想 2 灰狼捕食猎物过程 2.1 社会等级分层 2.2 包围猎物 2.3 狩猎 2.4 攻击猎物 2.5 寻找猎物 3 实现步骤及程序框图 3.1 步骤 3.2 程序框图 4 Python代码实现 5 Matlab实现 1 灰狼优化算法基本思想 灰狼优化算法是一种群智能优化算法&#xff0c;它的…

JAVA8 实体类集合多个字段组合排序

实体类集合多个字段组合排序&#xff0c;自由组合升降序&#xff0c;下面是参考代码示例&#xff1a; import lombok.Data;Data public class DbjrdmxDTO {private String djbh;private String rq; //订单日期private String ckdm;private String ckmc;private String newKhSig…

Coggle 30 Days of ML(23年7月)任务九:学会Bert基础,transformer库基础使用

Coggle 30 Days of ML&#xff08;23年7月&#xff09;任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 说明&#xff1a;在这个任务中&#xff0c;你将学习Bert模型的基础知识&#xff…

【使用字符串转换时间问题?】Tue Jul 11 23:59:59 CST 2023

问题展示&#xff1a;想要去除多余显示只显示&#xff08;时分秒&#xff1a;23:59:59&#xff09; 解决办法&#xff1a; 问题解决 实现代码&#xff1a; String dateString "2023-07-11 23:59:59";SimpleDateFormat inputFormat new SimpleDateFormat("…

异常处理一例

1.现象 代码片段&#xff1a; uint8_t CmdListener(char c) { #define CMD_SIZE 5static uint8_t cmdQueue[9];static uint8_t cmdReset[] { !, b, o, o, t};static uint8_t cmdYModem[] { 0x01, 0x00, 0xff };static uint8_t cmdIdx 0;int i;xlog("%c", 0xcc);…