小菜成長記(二)--策略工廠設計模式

寫一個商品結算程序:
public class Program {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("單價:");
        String numberOne = sc.next();
        System.out.println("數量:");
        String numberTwo = sc.next();
        System.out.println("打折率:");
        String rang = sc.next();

        if(!StringUtils.isNumeric(rang)){
            System.out.println("打折率輸入錯誤");
            System.exit(0);
        }

        // 獲取實際打折率
        float[] rangArr = new float[]{0,0.9f,0.8f,0.7f};
        float total = 0f;
        String rangStr = "不打折";
        try {
            switch (Integer.parseInt(rang)) {
                case 0 :
                    total = Float.parseFloat(numberOne) * Float.parseFloat(numberTwo);
                    rangStr = "不打折";
                    break;

                case 9 :
                    total = Float.parseFloat(numberOne) * Float.parseFloat(numberTwo) * rangArr[10 - Integer.parseInt(rang)];
                    rangStr = "打9折";
                    break;

                case 8 :
                    total = Float.parseFloat(numberOne) * Float.parseFloat(numberTwo) * rangArr[10 - Integer.parseInt(rang)];
                    rangStr = "打8折";
                    break;

                case 7 :
                    total = Float.parseFloat(numberOne) * Float.parseFloat(numberTwo) * rangArr[10 - Integer.parseInt(rang)];
                    rangStr = "打7折";
                    break;

                default:
                    throw new RuntimeException("不包含此種折扣");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("輸入的單價或者數量不是正數或者不包含此種折扣");
            System.exit(0);
        }
        System.out.println("總計:" + rangStr + "後 " + total);
    }
}
問題來了:“這樣子增加一個算法,就更改一下代碼,又不利於其他算法的保密,也不符合面向對象的三大特性”。
我:想起了上次的優化,使用簡單工廠設計模式改進一次。
public class Program {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("單價:");
        String price = sc.next();
        System.out.println("數量:");
        String number = sc.next();
        System.out.println("打折率:");
        String rang = sc.next();

        // 獲取實際打折率
        double[] rangArr = new double[]{0,0.9f,0.8f,0.7f};
        double total = 0f;
        try {
            CashSuper cash = CashFactory.createCash(rang);
            total = cash.acceptCash(Double.parseDouble(price) * Double.parseDouble(number)) ;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("輸入的單價或者數量不是正數或者不包含此種折扣");
            System.exit(0);
        }
        System.out.println("總計:" + rang + "後 " + total);
    }
}

abstract class CashSuper{
    public abstract double acceptCash(double money);
}

// 正常收費
class CashNormal extends CashSuper{
    @Override
    public double acceptCash(double money) {
        return money;
    }
}


// 打折收費
class CashRebate extends CashSuper{
    private double moneyRebate = 1l;

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

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

// 滿多少返利
class CashReturn extends CashSuper{
    private double moneyCondition = 0.0f;
    private double moneyReturn = 0.0f;

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

    @Override
    public double acceptCash(double money) {
        double result = money;
        if(money >= moneyCondition){
            result = money - Math.floor(money/moneyCondition)*moneyReturn;
        }
        return result;
    }
}

class CashFactory {
    public static CashSuper createCash(String rang) {
        CashSuper cash = null;
        switch (rang) {
            case "不打折":
                cash = new CashNormal();
                break;

            case "打9折":
                cash = new CashRebate(0.9f);
                break;

            case "打8折":
                cash =new CashRebate(0.8f);
                break;

            case "滿300送100":
                cash = new CashReturn(300,100);
                break;


            default:
                throw new RuntimeException("不包含此種折扣");
        }
        return cash;
    }
}
問題來了:“上面每增加一個算法都要更改工廠模式,重複利用代碼少了,有沒有更好的的設計模式呢”,最終找到了策略設計模式
public class Program {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("單價:");
        String price = sc.next();
        System.out.println("數量:");
        String number = sc.next();
        System.out.println("打折率:");
        String rang = sc.next();

        // 獲取實際打折率
        double[] rangArr = new double[]{0,0.9f,0.8f,0.7f};
        double total = 0f;
        CashContext cash = null;
        try {
            switch (rang) {
                case "不打折":
                    cash = new CashContext(new CashNormal());
                    break;

                case "打9折":
                    cash = new CashContext(new CashRebate(0.9f));
                    break;

                case "打8折":
                    cash = new CashContext(new CashRebate(0.8f));
                    break;

                case "滿300送100":
                    cash = new CashContext(new CashReturn(300, 100));
                    break;

                default:
                    throw new RuntimeException("不包含此種折扣");
            }
            total = cash.getResult(Double.parseDouble(price) * Double.parseDouble(number)) ;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("輸入的單價或者數量不是正數或者不包含此種折扣");
            System.exit(0);
        }
        System.out.println("總計:" + rang + "後 " + total);
    }
}

abstract class CashSuper{
    public abstract double acceptCash(double money);
}

// 正常收費
class CashNormal extends CashSuper{
    @Override
    public double acceptCash(double money) {
        return money;
    }
}

// 打折收費
class CashRebate extends CashSuper{
    private double moneyRebate = 1l;

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

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

// 滿多少返利
class CashReturn extends CashSuper{
    private double moneyCondition = 0.0f;
    private double moneyReturn = 0.0f;

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

    @Override
    public double acceptCash(double money) {
        double result = money;
        if(money >= moneyCondition){
            result = money - Math.floor(money/moneyCondition)*moneyReturn;
        }
        return result;
    }
}

class CashContext{
    private CashSuper strage;
    public CashContext(CashSuper strage) {
        this.strage = strage;
    }

    public double getResult(double money){
        return strage.acceptCash(money);
    }
}
仔細看了,這不是又回到了起點,還多封裝了一次。重複代碼更多了。又改如何改進?
策略與簡單工廠模式的結合
public class Program {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("單價:");
        String price = sc.next();
        System.out.println("數量:");
        String number = sc.next();
        System.out.println("打折率:");
        String rang = sc.next();

        // 獲取實際打折率
        double[] rangArr = new double[]{0,0.9f,0.8f,0.7f};
        double total = 0f;
        try {
            CashContext cash = new CashContext(rang);
            total = cash.getResult(Double.parseDouble(price) * Double.parseDouble(number)) ;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("輸入的單價或者數量不是正數或者不包含此種折扣");
            System.exit(0);
        }
        System.out.println("總計:" + rang + "後 " + total);
    }
}

abstract class CashSuper{
    public abstract double acceptCash(double money);
}

// 正常收費
class CashNormal extends CashSuper{
    @Override
    public double acceptCash(double money) {
        return money;
    }
}

// 打折收費
class CashRebate extends CashSuper{
    private double moneyRebate = 1l;

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

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

// 滿多少返利
class CashReturn extends CashSuper{
    private double moneyCondition = 0.0f;
    private double moneyReturn = 0.0f;

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

    @Override
    public double acceptCash(double money) {
        double result = money;
        if(money >= moneyCondition){
            result = money - Math.floor(money/moneyCondition)*moneyReturn;
        }
        return result;
    }
}

class CashContext{
    private CashSuper strage;
    public CashContext(String rang) {
        switch (rang) {
            case "不打折":
                strage = new CashNormal();
                break;

            case "打9折":
                strage = new CashRebate(0.9f);
                break;

            case "打8折":
                strage = new CashRebate(0.8f);
                break;

            case "滿300送100":
                strage = new CashReturn(300, 100);
                break;

            default:
                throw new RuntimeException("不包含此種折扣");
        }
    }

    public double getResult(double money){
        return strage.acceptCash(money);
    }
}
簡單工廠模式和策略簡單工廠模式的比較
簡單工廠模式 
CashSuper cash = CashFactory.createCash(rang);
total = cash.acceptCash(Double.parseDouble(price) * Double.parseDouble(number)) ;
策略工廠模式
CashContext cash = new CashContext(rang);
total = cash.getResult(Double.parseDouble(price) * Double.parseDouble(number)) ;
簡單工廠模式調用者需要認識兩個類,CashSuper和CashFactory,而策略工廠模式只要認識CashContext一個類。耦合程度更加降低


最後的反思:感覺策略模式用處並不是很大,只不過封裝了一次,讓調用者與算法分離。降低耦合度,但是代碼量增多了,閱讀複雜。更多等以後理解更深刻了,再補充。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章