设计模式之--(1)简单工厂模式|策略模式

最近深感项目面对需求改变时需要改动大量代码的烦恼
代码无错不是优,拒绝写bug!!!
于是学习<<大话设计模式>>,致力于写出优秀的代码,在此简单的做一下学习记录

简单工厂模式

→升级版的工厂方法模式简介

定义: 容器究竟需要实例化谁,将来会不会增加实例化对象,都是容易变化的地方,应该考虑用一个独立的类来做这个创建实例的地方,这就是工厂

定义永远只是定义,难于理解,亲自实现一次才是学习正道,下面直接贴代码

需求: 用户输入两个数字和一个符号,做符号的运算并输出结果
改变点:如果新增开根运算,如何处理

为简单工厂做准备

首先需求是对两个数字做一定的操作,那么我们先定义操作类

public class Operation {

	// 对应的get,set方法已省略
    private double numA = 0;
    private double numB = 0;

	// 通过该方法获取操作后的结果
    public double getRes() throws Exception {
        double res = 0;
        return res;
    }
    
}

其次针对每一种操作需要写一个子类,并重写计算方法

public class OperateSub extends Operation {

    public double getRes() {
        double res = getNumA() - getNumB();
        return res;
    }

}
public class OperateAdd extends Operation {

    public double getRes() {
        double res = getNumA() + getNumB();
        return res;
    }

}
public class OperateMul extends Operation {

    public double getRes() {
        double res = getNumA() * getNumB();
        return res;
    }
}
public class OperateDiv extends Operation {

    public double getRes() throws Exception {
        if (getNumB() == 0) {
            throw new Exception("分母不能为0");
        }
        double res = getNumA() / getNumB();
        return res;
    }
}

最后再写我们的工厂类

public class OperationFactory {

    public static Operation createOperation(String operate) {
        Operation oper = null;
        if ("+".equals(operate)) {
            oper = new OperateAdd();
        } else if ("-".equals(operate)) {
            oper = new OperateSub();
        } else if ("*".equals(operate)) {
            oper = new OperateMul();
        } else if ("/".equals(operate)) {
            oper = new OperateDiv();
        } else {
            // 如果新增开根运算,只需新建OperateRoot类
            // 继承Operation并重写getRes()方法
            // 并在此加入一个判断
        }
        return oper;
    }

}

测试我们的工厂

public static void main(String[] args) {

        try {
            Scanner scan = new Scanner(System.in);

            System.out.println("请输入数字a:");
            String strNumA = scan.nextLine();

            System.out.println("请输入运算符:");
            String strOperate = scan.nextLine();

            System.out.println("请输入数字b:");
            String strNumB = scan.nextLine();

            Operation oper = null;
            oper = OperationFactory.createOperation(strOperate);

            oper.setNumA(Double.parseDouble(strNumA));
            oper.setNumB(Double.parseDouble(strNumB));
            System.out.println(oper.getRes());

        } catch (Exception e) {
            System.out.println("您的输入有误");
            e.printStackTrace();
        }

    }

优点

通过封装将
我也不知道,自己领悟吧~
大概就是将代码之间的耦合度降低,调用者不再需要关心创建何种实例(这一步交给了工厂去完成),如果再新增别的计算方法,调用者无需改动,而新增的逻辑也不会影响原有的逻辑

策略模式

定义: 它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户

只要在分析过程中听到需要在不同时间 应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性

需求:商场收银软件,根据购买商品的单价和数量,显示收费信息
变化点:后续如果新增打折功能,再增加满减功能该如何实现计算实际收费的信息

策略的设计

目的:使用不同的算法,根据应收总额计算实际需要收取费用

先定义接口,需要有计算现金的功能

public interface CashSuper {

    double acceptCash(double money);

}

其次实现各个算法类,实现接口

// 正常收费
public class CashNormal implements CashSuper {

    @Override
    public double acceptCash(double money) {
        return money;
    }

}
// 打折
public class CashRebate implements CashSuper {

    private double moneyRebate = 0;

    public CashRebate(double moneyRebate) {
        this.moneyRebate = moneyRebate;
    }

    @Override
    public double acceptCash(double money) {
        return money * moneyRebate;
    }
}
// 满减
public class CashReturn implements CashSuper {

    private double moneyCondition = 0;
    private double moneyReturn = 0;

    public CashReturn(double moneyCondition, double moneyReturn) {
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    @Override
    public double acceptCash(double money) {
        double res = money;

        if (money >= moneyCondition) {
            res = money - Math.floor(money / moneyCondition) * moneyReturn;
        }

        return res;
    }
}

实现上下文类,维护策略的使用

public class CashContext {

    private CashSuper cs;

    public CashContext(CashSuper cs) throws Exception {
		this.cs = cs;
    }

    public double getResult(double money) {
        return cs.acceptCash(money);
    }

}

测试代码

public static void main(String[] args) throws Exception {

        double total = 100;
		String type = "";

        CashContext cc = null;
        CashSuper cs = null;
        if ("正常收费".equals(type)) {
            cs = new CashNormal();
        } else if ("满300反100".equals(type)) {
            cs = new CashReturn(300, 100);
        } else if ("打8折".equals(type)) {
            cs = new CashRebate(0.8);
        } else {
            throw new Exception("没有所选算法");
        }
        cc = new CashContext(cs);

        total = cc.getResult(total);
        System.out.println(total);

    }

优化:简单工厂模式和策略模式结合

只需要修改两个类: 测试方法和CashContext

public class CashContext {

    private CashSuper cs;

    public CashContext(String type) throws Exception {

        if ("正常收费".equals(type)) {
            cs = new CashNormal();
        } else if ("满300反100".equals(type)) {
            cs = new CashReturn(300, 100);
        } else if ("打8折".equals(type)) {
            cs = new CashRebate(0.8);
        } else {
            throw new Exception("没有所选算法");
        }

    }

    public double getResult(double money) {
        return cs.acceptCash(money);
    }

}

测试方法:

public static void main(String[] args) throws Exception {

        double total = 100;
        String type = "打8折";

        CashContext cc = new CashContext(type);

        total = cc.getResult(total);
        System.out.println(total);

    }

总结

简单工厂模式和策略模式的结合,使得客户端本需要认识CashSuper和CashFactory变成了只需要认识CashContext
耦合度进一步降低

在结构上两个例子很相似,但是:
简单工厂模式的重点在于:使用工厂来封装创建实例的过程,使得客户端不再需要关注于此,直接使用即可
策略模式的重点在于: 将各种算法分开写,然后以相同的方式调用所有的算法,减少了算法的实现与调用者之间的耦合,策略模式封装了变化,其次简化了单元测试,每个算法单独写各自的测试用例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值