当前位置: 首页 > article >正文

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

目录

    • 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{@Overridepublic void callPhone() {System.out.println("正在使用华为手机打电话");}
}// 定义具体子类产品实现
public class XiaoMiPhone implements Phone{@Overridepublic 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{@Overridepublic void car() {System.out.println("Huawei car");}
}// 具体子类产品实现
public class XiaomiCar implements Car{@Overridepublic void car() {System.out.println("Xiaomi SU7 Ultra");}
}// 抽象工厂 ,返回产品接口
public abstract class CarFactory {public abstract Car fetchCar();
}// 定义子类工厂
public class HuaweiFactory extends CarFactory {@Overridepublic Car fetchCar() {return new HuaweiCar();}
}// 定义子类工厂
public class XiaomiFactory extends CarFactory {@Overridepublic 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{@Overridepublic double fetchPrice(double price, int num) {return price * num;}
}// 定义子类的策略
public class IntermediateStrategy implements IntegrationStrategy{@Overridepublic double fetchPrice(double price, int num) {return price * num - (price * num * 0.2);}
}// 定义子类的策略
public class AdvancedStrategy implements IntegrationStrategy {@Overridepublic 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.lryc.cn/news/2392174.html

相关文章:

  • 【Echarts】象形图
  • git 本地合并怎么撤回
  • 集星云推短视频矩阵系统的定制化与私有化部署方案
  • npm run build 报错:Some chunks are larger than 500 KB after minification
  • XCTF-web-file_include
  • 5.28 后端面经
  • CPP中CAS std::chrono 信号量与Any类的手动实现
  • PHP生成pdf方法
  • 【Android笔记】记一次 CMake 构建 Filament Android 库的完整排错过程(安卓交叉编译、CMake、Ninja)
  • C#中的BeginInvoke和EndInvoke:异步编程的双剑客
  • 告别延迟!modbus tcp转profine网关助力改造电厂改造升级
  • 《软件工程》第 5 章 - 需求分析模型的表示
  • 解释k8s种ConfigMap和Secret的作用,如何在Pod中挂载环境变
  • 阿里云国际版香港轻量云服务器:CN2 GIA加持,征服海外网络的“速度与激情”!
  • Qt6无法识别OpenCV(Windows端开发)
  • 二、网络安全常见编码及算法-(2)
  • Windows系统安装MySQL Connector 使用C++ VS2022连接MySQL
  • D2000平台上Centos使用mmap函数遇到的陷阱
  • Elasticsearch索引机制与Lucene段合并策略深度解析
  • BPE、WordPiece 与 Unigram:三种主流子词分词算法对比
  • 青少年编程与数学 02-020 C#程序设计基础 11课题、可视化编程
  • AI时代新词-AI驱动的自动化(AI - Driven Automation)
  • 整合Jdk17+Spring Boot3.2+Elasticsearch9.0+mybatis3.5.12的简单用法
  • Starrocks 物化视图的实现以及在刷新期间能否读数据
  • 前后端传输 Long 类型数据时(时间戳,雪花算法ID),精度丢失的根本原因
  • 探索容器技术:Docker与Kubernetes的实践指南
  • Ubuntu从0到1搭建监控平台:本地部署到公网访问实战教程Cpolar穿透与Docker部署全过程
  • vscode java debug terminal 中文乱码
  • 3D PDF如何制作?SOLIDWORKS MBD模板定制技巧
  • Qt DateTimeEdit(时间⽇期的微调框)