DesignMode_StrategyMode

策略模式 -- 其实就是封装了不同算法的一种方式,让客户端代码只需要跟那个策略类进行交互,而不需要进行再与底层的其他什么类进行交互,耦合度大大的降低

情景 :写一个商场打折促销的收费系统,促销方式有 : 打0.8折, 满500减200, 还有正常收费

思路 :因为促销的方式分了几种,但是目的都是一样的,就是算最终的收费金额,所以,当方式不同,但目的一样时,就可以用工厂方法,

上代码

首先先定义一个父类来总结几个子类的接口,这个时候,就可以用抽象类,因为,这个类是几个具体方式的抽象出来的总结,不需要实例化

package strategicMode;

/* 对收钱的概念的抽象
 * */ 

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

然后是那几个具体方式的实现

package strategicMode;

/*
 * 正常收费区
 * */

public class CashNormal extends CashSuper{
    public CashNormal(){
        
    }
    @Override
    public double getResult(double money) {

        return money;
    }
}
package strategicMode;

/*
 * 折扣区
 * */

public class CashRebate extends CashSuper{
    private double rebate;
    private double result;
    public CashRebate(double rebate) {
        this.rebate = rebate;
    }
    
    public double getResult(double money) {
        result = money*rebate;
        return result;
    }
}
package strategicMode;

/*
 * 返利区
 * */
public class CashReturn extends CashSuper{
    private double minMon;
    private double returnMon;
    private double result;
    public CashReturn(double minMon, double returnMon) {
        this.minMon = minMon;
        this.returnMon = returnMon;
    }
    

    @Override
    public double getResult(double money) {
        if(money > minMon){
            result = money - returnMon;
        }
        return result;
    }
}

好了,下面就是套路了,写个工厂类判别什么时候调用哪个促销收费方式

package strategicMode;

/*
 *  促销方式的工厂方法
 * */

public class CashWayFactory {
    CashSuper cashWay;
    public CashSuper getCashAcceptWay(String cashAcceptWay){
        
        switch(cashAcceptWay){
        case "打八折": cashWay = new CashRebate(0.8);
                     break;
        case "正常收费" : cashWay = new CashNormal();
                        break;
        case "满500返200" : cashWay = new CashReturn(500, 200);
                        break;
        }
        return cashWay;
    }
}

客户端代码

package strategicMode;

import java.util.Scanner;

import org.junit.Test;

/*
 * 客户端代码
 * */

public class ClientCode {
    CashWayFactory cashWayFactoy = new CashWayFactory();
    CashSuper cashWay;
    @Test
    public void testCashWay(){
        System.out.println("请输入你的收费方式(打八折, 正常收费, 满500返200)");
        Scanner in = new Scanner(System.in);
        String cashAcceptWay = in.next();
        System.out.println("请输入总费用:");
        double money = in.nextDouble();
        cashWay = cashWayFactoy.getCashAcceptWay(cashAcceptWay);
        double result = cashWay.getResult(money);
        System.out.println("你需要交的总费用: "+result);
    }
}

但是上面的代码灵活性不是很高,当我需求改变了,要加一些其他的促销方式时,就还是要在工厂里面进行改动和维护,导致整个代码需要重新编译部署,包括了客户端的代码,引用客户端的代码是直接和工厂方法进行了交互的,所以这样来说还是非常鸡肋的。于是就有了策略方式

策略模式 就是一种可以封装不同算法的方式,最终得到一个不同算法,但目的一样的值,简单明了的就是封装了变化性

package strategicMode;

/*
 * 维护对CashSuper对象的引用 
 * */

public class StrategeContext {
    CashSuper cashWay;
    
    // 策略模式与工厂相结合
    public StrategeContext(String cashWayString) {

        switch(cashWayString){
        case "打八折": cashWay = new CashRebate(0.8);break;
        case "正常收费" : cashWay = new CashNormal();break;
        case "满500返200" : cashWay = new CashReturn(500, 200);break;
        }
        
    }
    
    // 现在我要的需求是 : 客户端的代码只需要调用这个方法就可以得到相应的结果了
    public double cashAcceptWay(double money){
        return cashWay.getResult(money);
    }
}

上面的策略类就是把所有不同的算法方式,都封装到一起了,现在只是需要得到一个值返回给客户端,而客户端的代码也会变得十分简洁

package strategicMode;

import java.util.Scanner;

import org.junit.Test;

/*
 * 拥有
 * */
public class ClientCode2_0 {
    StrategeContext context;
    @Test
    public void testCashWay(){
        System.out.println("请输入总共花费:");
        Scanner in = new Scanner(System.in);
        double cash = in.nextDouble();
        System.out.println("请输入你的收费方式(打八折, 正常收费, 满500返200)");
        String cashWayString = in.next();
        context = new StrategeContext(cashWayString);
        
        System.out.println("你应该收取的费用是 : "+context.cashAcceptWay(cash));
    }
}

可以看到客户端只需要有一个策略类就能得到相应的结果,而不需要再跟工厂和促销方式这些底层的东西打交道了。。。就相当于,现在已经从经理直接升级为了ceo了,我只需要一个策略,其余的让下面的人去做,我不需要管,而策略类就是部署下面的人去做的中间商,可以看作经理。但是这个代码终归是不完整的,因为还有一个重要的问题没有解决,就是,我每次新加入一个需求促销方式,都要去策略类哪里部署,让他去做,这也是很麻烦的,所以就会引入反射这个方式,后面的blog我会继续提到。

原文地址:https://www.cnblogs.com/AmoryWang-JavaSunny/p/6517811.html