Java设计模式之工厂模式与策略模式简单案例学习

news2025/5/31 22:21:50

目录

    • 1.前言
    • 2.工厂模式
      • 2.1 简单工厂方法
      • 2.2 静态工厂方法
      • 2.3 抽象工厂方法
    • 3.策略模式
    • 4.区别与联系
      • 4.1定义与核心意图
      • 4.2 UML 结构对比
      • 4.3 关键组成对比
      • 4.4 应用场景对比

1.前言

       最近接手的项目真的是太无语了,经历了多数人的编写,什么牛马鬼神写法都有,大量的 if-else,一个方法几千行,维护起来特别头大,造成这种原因就是没有充分的利用设计模式,利用设计模式编写的代码,后期维护和扩展都特别容易,下面就通过几个简单案例了解下设计模式的玩法;

2.工厂模式

2.1 简单工厂方法

// 定义一个产品接口
public interface Phone {
    void callPhone();
}

// 定义具体子类产品实现
public class HuaWeiPhone implements Phone{
    @Override
    public void callPhone() {
        System.out.println("正在使用华为手机打电话");
    }
}

// 定义具体子类产品实现
public class XiaoMiPhone implements Phone{
    @Override
    public void callPhone() {
        System.out.println("正在使用小米手机打电话");
    }
}

// 定义工厂,提供一个公共获取产品接口的方法
public class PhoneFactory {
    public Phone fetchPhone(String certificate) {
        switch (certificate) {
            case "xiaomi":
                return new XiaoMiPhone();
            case "huawei":
                return new HuaWeiPhone();
            default:
                System.out.println("无法解析凭证");
                return null;
        }
    }
}

// 测试
public class SimpleTest {
    public static void main(String[] args) {
        // 创建工厂
        PhoneFactory phoneFactory = new PhoneFactory();
        // 获取具体工厂实例
        Phone xiaomi = phoneFactory.fetchPhone("xiaomi");
        xiaomi.callPhone(); //输出: 正在使用小米手机打电话
    }
}

玩法步骤:
    1.创建一个产品接口
    2.创建子类去实现接口
    3.创建工厂,给定一个获取实例对象的方法
        优点:主业务部分不关心具体实例的创建细节,把创建的逻辑解耦出去
        缺点:每次有新添加的子类,都需要改动工厂类(不管是调整工厂类为多方法,还是指定字符),违反了外开内闭的原则

2.2 静态工厂方法

    对于上述工厂方法调用中,每次都需要去实例化工厂,特别麻烦,可以把工厂静态化,直接调用;

// 在工厂提供类中直接静态实例化子类工厂
public class ManyFactory {
    public static Phone fetchXiaomiPhone() {
        return new XiaoMiPhone();
    }

    public static Phone fetchHuaweiPhone() {
        return new HuaWeiPhone();
    }
}

// 测试
public class ManyFactoryTest {
    public static void main(String[] args) {
        Phone phone = ManyFactory.fetchHuaweiPhone();
        phone.callPhone();// 输出:正在使用华为手机打电话
    }
}

不管怎么去调整,原则上都是工厂方法,每次添加子类工厂,都需要改变工厂提供类,违反了外开内闭的原则,所以引入了抽象工厂,就可以很好的解决这个问题;

2.3 抽象工厂方法

// 定义产品接口
public interface Car {
    void car();
}

// 具体子类产品实现
public class HuaweiCar implements Car{
    @Override
    public void car() {
        System.out.println("Huawei car");
    }
}

// 具体子类产品实现
public class XiaomiCar implements Car{
    @Override
    public void car() {
        System.out.println("Xiaomi SU7 Ultra");
    }
}

// 抽象工厂 ,返回产品接口
public abstract class CarFactory {
    public abstract Car fetchCar();
}

// 定义子类工厂
public class HuaweiFactory extends CarFactory {
    @Override
    public Car fetchCar() {
        return new HuaweiCar();
    }
}

// 定义子类工厂
public class XiaomiFactory extends CarFactory {
    @Override
    public Car fetchCar() {
        return new XiaomiCar();
    }
}

// 测试
public class AbstractFactoryTest {
    public static void main(String[] args) {
        XiaomiFactory xiaomiFactory = new XiaomiFactory();
        Car car = xiaomiFactory.fetchCar();
        car.car();// 输出: Xiaomi SU7 Ultra
    }
}

玩法:
    1.创建一个产品接口
    2.创建具体子类实现接口
    3.创建一个抽象工厂接口,定义一个抽象方法,返回产品接口
将工厂抽象出来,由子工厂去实现创建实例,对外的扩展性好,新增产品时,只需要增加子工厂即可

3.策略模式

一个策略多种实现,把具体的实现都封装起来,提供一个策略接口,通过上下文进行封装,在外部调用即可,有新策略,添加子策略即可

// 定义策略接口
public interface IntegrationStrategy {
    /**
     * 获取价格
     * @param price 总价
     * @param num 数量
     */
    double fetchPrice(double price,int num);
}

// 定义子类的策略
public class OrdinaryStrategy implements IntegrationStrategy{
    @Override
    public double fetchPrice(double price, int num) {
        return price * num;
    }
}

// 定义子类的策略
public class IntermediateStrategy implements IntegrationStrategy{
    @Override
    public double fetchPrice(double price, int num) {
        return price * num - (price * num * 0.2);
    }
}

// 定义子类的策略
public class AdvancedStrategy implements IntegrationStrategy {
    @Override
    public double fetchPrice(double price, int num) {
        return (price * num) - (price * num * 0.4);
    }
}

// 定义上下文进行封装策略接口
public class IntegrationContext {

    // 定义属性:策略接口
    private final IntegrationStrategy integrationStrategy;

    public IntegrationContext(IntegrationStrategy integrationStrategy) {
        this.integrationStrategy = integrationStrategy;
    }

    // 提供一个可策略接口的执行方法
    public double executeIntegration(double price,int num) {
        return integrationStrategy.fetchPrice(price,num);
    }

}

// 这里的策略可以考虑抽成一个简单工厂的方法,方便外部调用管理
public class StrategyFactory {
    public static IntegrationStrategy fetchStrategy(String sign) {
        switch (sign) {
            case  "Ordinary" :
                return new OrdinaryStrategy();
            case "Advanced" :
                return new AdvancedStrategy();
            case "Intermediate" :
                return new IntermediateStrategy();
            default:
                System.out.println("未支持的标识");
                return null;
        }
    }
}

//测试
public class StrategyTest {
    public static void main(String[] args) {
        // 获取具体策略
        IntegrationStrategy strategy = StrategyFactory.fetchStrategy("Advanced");
        // 通过上下文 调用策略方法
        IntegrationContext context = new IntegrationContext(strategy);
        double integration = context.executeIntegration(250, 3);
        System.out.println("折扣的价格是:" + integration);// 输出:450
    }
}

玩法:
    1.创建一个策略接口
    2.创建具体子类策略实现接口
    3.创建一个上下文(定义属性:策略接口,有参构造方法,提供提供一个可策略接口的执行方法)

4.区别与联系

4.1定义与核心意图

    通过上述简单的案例可以了解到两者的区别与联系

模式定义目的
抽象工厂模式提供一个创建一系列相关或依赖对象的接口,而无需指定它们的具体类解决产品族对象创建的问题,隐藏具体类
策略模式定义一系列算法,将每个算法封装起来,并使它们可以互换在运行时选择算法或行为,提高灵活性

4.2 UML 结构对比

抽象工厂模式 UML 简图:
	          	   AbstractFactory
          			/          \
			ProductAFactory  ProductBFactory
    				|                |
				ProductA         ProductB
				
策略模式 UML 简图:
       				    Context
          			       |
         			  Strategy(接口)
         				 /      \
   					StrategyA  StrategyB

4.3 关键组成对比

对比项抽象工厂模式策略模式
设计意图创建一系列产品对象(产品族)动态选择行为或算法
核心角色抽象工厂、具体工厂、抽象产品、具体产品上下文(Context)、策略接口、具体策略类
关注点产品的创建过程行为的动态切换
变化点工厂类与产品族策略行为的实现类

4.4 应用场景对比

场景抽象工厂模式策略模式
操作系统平台相关的 GUI 工厂(Windows / Linux)
算法切换:排序算法、压缩算法、支付方式等
产品对象有多个等级结构且系统需要独立于产品的创建过程
动态改变行为(如日志策略、推荐算法)

虽然两种设计模式有着诸多的不同,解决的问题也不同,但它们也可以组合使用;
下一文章就结合日常支付的场景做个结合使用的案例;

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

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

相关文章

【Echarts】象形图

目录 效果代码 效果 代码 <!-- 业务类型 --> <template><div class"ywlx" :style"{ --height: height }"><div class"header_count count_linear_bg"><div>当月业务总量<span class"common_count text_s…

集星云推短视频矩阵系统的定制化与私有化部署方案

在当今数字化营销时代&#xff0c;短视频矩阵系统成为众多企业和机构拓展影响力、实现精准营销的关键工具。集星云推短视频矩阵系统凭借其强大的功能和灵活的定制性&#xff0c;为企业提供了全方位的解决方案。 一、API接口定制&#xff1a;无缝对接自有系统 集星云推短视频矩…

XCTF-web-file_include

解析 <?php highlight_file(__FILE__); // 高亮显示当前PHP文件源代码 include("./check.php"); // 包含检查文件&#xff08;可能包含安全过滤逻辑&#xff09;if(isset($_GET[filename])) { // 检查是否传入filename参数$filename $_GET[f…

5.28 后端面经

为什么golang在并发环境下更有优势 Go语言&#xff08;Golang&#xff09;在并发环境下的优势主要源自其设计哲学和内置的并发机制&#xff0c;这些机制在语言层面提供了高效、简洁且安全的并发编程工具。以下是其核心优势的详细分析&#xff1a; 1. Goroutine&#xff1a;轻量…

CPP中CAS std::chrono 信号量与Any类的手动实现

前言 CAS&#xff08;Compare and Swap&#xff09; 是一种用于多线程同步的原子指令。它通过比较和交换操作来确保数据的一致性和线程安全性。CAS操作涉及三个操作数&#xff1a;内存位置V、预期值E和新值U。当且仅当内存位置V的值与预期值E相等时&#xff0c;CAS才会将内存位…

PHP生成pdf方法

1&#xff1a;第一种方法&#xff1a; 主要使用PHP的扩展 【 “spatie/browsershot”: “3.57”】 使用这个扩展生成PDF需要环境安装以下依赖 1.1&#xff1a;NPM【版本&#xff1a;9.2.0】 1.2&#xff1a;NODE【版本&#xff1a;v18.19.1】 1.3&#xff1a;puppeteer【npm in…

【Android笔记】记一次 CMake 构建 Filament Android 库的完整排错过程(安卓交叉编译、CMake、Ninja)

写在前面的话&#xff0c;为了保持Sceneform-EQR始终是采用最新的filament&#xff0c;每隔一段时间我都会编译filament&#xff0c;并根据新增内容完善Sceneform-EQR。 现由于更换电脑&#xff0c;环境需重新配置。简单记录下编译出错和解决方式。 Sceneform-EQR 是EQ对谷歌“…

C#中的BeginInvoke和EndInvoke:异步编程的双剑客

文章目录 引言1. BeginInvoke和EndInvoke的基本概念1.1 什么是BeginInvoke和EndInvoke1.2 重要概念解释 2. 委托中的BeginInvoke和EndInvoke2.1 BeginInvoke方法2.2 EndInvoke方法2.3 两者的关系 3. 使用方式与模式3.1 等待模式3.2 轮询模式3.3 等待句柄模式3.4 回调模式 4. 底…

告别延迟!modbus tcp转profine网关助力改造电厂改造升级

发电需求从未如此旺盛。无论您是为客户发电还是为自身运营发电&#xff0c;您都需要提高运营效率&#xff0c;并在资产老化、资源萎缩的情况下&#xff0c;紧跟不断变化的法规。如今&#xff0c;智能系统和技术能够帮助您实现运营转型&#xff0c;提高可视性并实现关键流程自动…

《软件工程》第 5 章 - 需求分析模型的表示

目录 5.1需求分析与验证 5.1.1 顺序图 5.1.2 通信图 5.1.3 状态图 5.1.4 扩充机制 5.2 需求分析的过程模型 5.3 需求优先级分析 5.3.1 确定需求项优先级 5.3.2 排定用例分析的优先顺序 5.4 用例分析 5.4.1 精化领域概念模型 5.4.2 设置分析类 5.4.3 构思分析类之间…

阿里云国际版香港轻量云服务器:CN2 GIA加持,征服海外网络的“速度与激情”!

阿里云国际版香港轻量云服务器&#xff1a;CN2 GIA加持&#xff0c;征服海外网络的“速度与激情”&#xff01; 面对全球化业务拓展对网络连接的严苛要求&#xff0c;阿里云国际版香港轻量云服务器正成为出海企业和开发者的新宠。其核心优势在于搭载了CN2 GIA&#xff08;Glob…

Qt6无法识别OpenCV(Windows端开发)

这段时间在Windows 10上进行Qt6的开发。结果在build过程中&#xff0c;出现了如下错误: 但实际上&#xff0c;我明明安装了OpenCV4.10.0, 并且也在CMakeLists.txt中加入了相关内容。 但是&#xff0c;注意自己的编译输出: [1/5 1.4/sec] Automatic MOC and UIC for target R…

二、网络安全常见编码及算法-(2)

该文章主要介绍古典密码和隐写常用的密码和编码&#xff0c;日常中很少见&#xff0c;主要用于ctf比赛和考试学习一、古典密码 1、古典密码概念概述 古典密码是密码学发展早期所使用的一系列加密技术&#xff0c;这些密码主要依靠手工操作或简单的机械装置来实现信息的加密和…

Windows系统安装MySQL Connector 使用C++ VS2022连接MySQL

1. 官网及版本 1.1. 网址 官方文档 - 安装编译构建&#xff1a; https://dev.mysql.com/doc/connector-cpp/9.3/en/ 官方文档 - 使用案例&#xff1a; https://dev.mysql.com/doc/dev/connector-cpp/latest/ 下载地址&#xff1a; https://dev.mysql.com/downloads/connector/…

D2000平台上Centos使用mmap函数遇到的陷阱

----------原创不易&#xff0c;欢迎点赞收藏。广交嵌入式开发的朋友&#xff0c;讨论技术和产品------------- 在飞腾D2000平台上&#xff0c;安装了麒麟linux系统&#xff0c;我写了个GPIO点灯的程序&#xff0c;在应用层利用mmap函数将内核空间映射到用户态&#xff0c;然后…

Elasticsearch索引机制与Lucene段合并策略深度解析

引言 在现代分布式搜索引擎Elasticsearch中&#xff0c;文档的索引、更新和删除操作不仅是用户交互的核心入口&#xff0c;更是底层存储架构设计的关键挑战。本文围绕以下核心链路展开&#xff1a; 文档生命周期管理&#xff1a;从客户端请求路由到分片定位&#xff0c;从内存…

整合Jdk17+Spring Boot3.2+Elasticsearch9.0+mybatis3.5.12的简单用法

Elasticsearch是一个基于Lucene的分布式搜索和分析引擎&#xff0c;广泛应用于全文搜索、日志分析等场景。结合Spring Boot可以快速构建强大的搜索应用。本文将介绍如何在Spring Boot项目中集成和使用Elasticsearch。 ES9.0.1目前支持的包只有 elasticsearch-rest-client/ …

Ubuntu从0到1搭建监控平台:本地部署到公网访问实战教程Cpolar穿透与Docker部署全过程

文章目录 前言1.关于Ward2.Docker部署3.简单使用ward4.安装cpolar内网穿透5. 配置ward公网地址6. 配置固定公网地址总结 前言 IT运维人员是否常为服务器管理系统的复杂操作所困扰&#xff1f;当海量性能指标图表与密集预警信号同时涌现时&#xff0c;这种信息过载往往让专业团…

vscode java debug terminal 中文乱码

现象 解决 快捷键 ctrl , 进入setting 配文件添加 "terminal.integrated.automationProfile.windows": {"path": "cmd","args": ["/k","chcp","65001"]}terminal 启动时&#xff0c;活动也改为 utf-…

3D PDF如何制作?SOLIDWORKS MBD模板定制技巧

SOLIDWORKS制作3D PDF模版 SOLIDWORKS MBD能够帮助工程师以清晰直观的方式描述产品尺寸信息。在3D PDF文件中&#xff0c;用户可以自由旋转和移动视图&#xff0c;方便查看模型的各个尺寸细节。 本文将带您一步步学习如何使用SOLIDWORKS MBD制作专业的3D PDF模板&#xff0c;…