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

目录

1.前言

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

2.工厂模式

2.1 简单工厂方法

java 复制代码
// 定义一个产品接口
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 静态工厂方法

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

java 复制代码
// 在工厂提供类中直接静态实例化子类工厂
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 抽象工厂方法

java 复制代码
// 定义产品接口
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.策略模式

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

java 复制代码
// 定义策略接口
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 结构对比

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

4.3 关键组成对比

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

4.4 应用场景对比

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

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

相关推荐
今天也想快点毕业2 分钟前
【SQL Server Management Studio 连接时遇到的一个错误】
java·服务器·数据库
向哆哆7 分钟前
Java 大数据处理:使用 Hadoop 和 Spark 进行大规模数据处理
java·hadoop·spark
珊珊而川10 分钟前
`docker commit` 和 `docker save`区别
java·docker·eureka
江节胜-胜行全栈AI31 分钟前
Java-代码段-http接口调用自身服务中的其他http接口(mock)-并建立socket连接发送和接收报文实例
java·开发语言·http
猛犸MAMMOTH1 小时前
Python打卡第40天
开发语言·python·机器学习
写bug写bug1 小时前
一文掌握 Spring 的启动扩展点
java·后端·spring
别来无恙1491 小时前
Java枚举详解:从基础到高级应用
java·开发语言·枚举
地藏Kelvin1 小时前
Spring Ai 从Demo到搭建套壳项目(一)初识与实现与deepseek对话模式
java·人工智能·后端
论迹1 小时前
【JavaEE】-- 文件操作和IO
java·java-ee·io·文件操作
程序员清风1 小时前
快手一面:RocketMQ顺序消息如何增加吞吐量?
java·后端·面试