大话设计模式-策略模式

本文转载自点击打开链接
需求
实现一份金庸知识考试的试卷。
实现
级别1

public class Cash  
{  
    private double  total = 0;  
    public void submit(int num, double price)  
    {  
        double totalPrices = num * price;  
        total += totalPrices;  
        System.out.println("单价:" + price + " 数量:" + num + "合计:" + totalPrices);  
    }  
    public double getTotal()  
    {  
        return total;  
    }  
    public void setTotal(double total)  
    {  
        this.total = total;  
    }  
}  
级别2

增加打折的功能。

public class Cash  
{  
    private double  total           = 0;  
    private int     selectedIndex   = 0;  
    public void selectFormLoad()  
    {  
        String[] selectForm = { "正常收费", "打8折", "打7折", "打5折" };  
        selectedIndex = 0;  
    }  
    public void submit(int num, double price)  
    {  
        double totalPrices = 0;  
        switch (selectedIndex)  
        {  
            case 0:  
                totalPrices = num * price;  
                break;  
            case 1:  
                totalPrices = num * price * 0.8;  
                break;  
            case 2:  
                totalPrices = num * price * 0.7;  
                break;  
            case 3:  
                totalPrices = num * price * 0.5;  
                break;  
        }  
        total += totalPrices;  
        System.out.println("单价:" + price + " 数量:" + num + "合计:" + totalPrices);  
    }  
    public double getTotal()  
    {  
        return total;  
    }  
    public void setTotal(double total)  
    {  
        this.total = total;  
    }  
    public int getSelectedIndex()  
    {  
        return selectedIndex;  
    }  
    public void setSelectedIndex(int selectedIndex)  
    {  
        this.selectedIndex = selectedIndex;  
    }  
}  

级别3

面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同的属性和功能的对象的抽象集合才是类。打1折和打9折只是形式不同,抽象分析出来,所有的打折算法都是一样的,所以打折算法应该是一个类。我们来试着用上次讲过的简单工厂模式实现。

//现金收费接口  
public interface CashSuper  
{  
    public double acceptCash(double money);  
}  
//正常收费子类  
public class CashNormal implements CashSuper  
{  
    public double acceptCash(double money)  
    {  
        return money;  
    }  
} 
//打折收费子类  
public class CashRebate implements CashSuper  
{  
    private double  moneyRebate = 1;  
    public CashRebate(double moneyRebate)  
    {  
        this.moneyRebate = moneyRebate;  
    }  
    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;  
    }  
    public double acceptCash(double money)  
    {  
        double result = money;  
        if (money >= moneyCondition)  
        { 
            int temp=(int)(money/moneyCondition);
            result = money -temp* moneyReturn;  
        }  
        return result;  
    }  
} 
//现金收费工厂类  
public class CashFactory  
{  
    public static CashSuper createCash(String type)  
    {  
        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);  
        }  
        return cs;  
    }  
} 
//客户端代码 
public class Main  
{  
    private static double total = 0;  
    public static void main(String[] args)  
    {  
        consume("正常收费", 1, 1000);  
        consume("满300返100", 1, 1000);  
        consume("打8折", 1, 1000);  
        System.out.println("总计:" + total);  
    }  
    public static void consume(String type, int num, double price)  
    {  
        CashSuper csuper = CashFactory.createCash(type);  
        double totalPrices = 0;  
        totalPrices = csuper.acceptCash(num * price);  
        total += totalPrices;  
        System.out.println("单价:" + price + " 数量:" + num + "合计:" + totalPrices);  
    }  
} 
简单工厂模式虽然也能解决这个问题,但是这个模式只是解决对象的创建问题,而且由于工厂本身包括了所有的收费方式,商场是可能经常性地更改打折额度和返利额度的,每次维护或扩展收费方式都要改动这个工厂,以致代码需要重新编译部署,这是非常糟糕的处理方式,所以用它不是最好的办法。面对算法的时常变动,应该有更好的办法。

级别4

策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
商场收银时,如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,这没有错,但算法本身只是一种策略,最重要的是这些算法是随时都可能互相替换的,而封装变化点是我们面向对象的一种很重要的思维方式。

策略模式的基本代码:

//Strategy类,定义所有支持的算法的公共接口  
public interface Strategy  
{  
    public void algorithmInterface();  
}  
//ConcreteStrategy封装了具体的算法或行为,继承于Strategy  
public class ConcreteStrategyA implements Strategy  
{  
    public void algorithmInterface()  
    {  
        System.out.println("算法A实现");  
    }  
}  
public class ConcreteStrategyB implements Strategy  
{  
    public void algorithmInterface()  
    {  
        System.out.println("算法A实现");  
    }  
}  
public class ConcreteStrategyC implements Strategy  
{  
    public void algorithmInterface()  
    {  
        System.out.println("算法C实现");  
    }  
}  
//Context用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用  
public class Context  
{  
    private Strategy strategy;  
    public Context(Strategy strategy)  
    {  
        this.strategy = strategy;  
    }  
    public void contextInterface()  
    {  
        strategy.algorithmInterface();  
    }  
}  
//客户端代码  
public class Main  
{  
    public static void main(String[] args)  
    {  
        Context context;  
        context = new Context(new ConcreteStrategyA());  
        context.contextInterface();  
        context = new Context(new ConcreteStrategyB());  
        context.contextInterface();  
        context = new Context(new ConcreteStrategyC());  
        context.contextInterface();  
    }  
}  
加一个CashContext类,去掉CashFactory类,并改一下客户端就可以了。
//CashContext类  
public class CashContext  
{  
    CashSuper cashSuper;  
    public CashContext(CashSuper cashSuper)  
    {  
        this.cashSuper = cashSuper;  
    }  
    public double acceptCash(double money)  
    {  
        return cashSuper.acceptCash(money);  
    }  
}  
//客户端代码 
public class Main  
{  
    private static double total = 0;  
    public static void main(String[] args)  
    {  
        consume("正常收费", 1, 1000);  
        consume("满300返100", 1, 1000);  
        consume("打8折", 1, 1000);  
        System.out.println("总计:" + total);  
    }  
    public static void consume(String type, int num, double price)  
    {  
        CashContext cashContext = null;  
        if ("正常收费".equals(type))  
        {  
            cashContext = new CashContext(new CashNormal());  
        }  
        else if ("满300返100".equals(type))  
        {  
            cashContext = new CashContext(new CashReturn(300, 100));  
        }  
        else if ("打8折".equals(type))  
        {  
            cashContext = new CashContext(new CashRebate(0.8));  
        }  
        double totalPrices = cashContext.acceptCash(num * price);  
        total += totalPrices;  
        System.out.println("单价:" + price + " 数量:" + num + "合计:" + totalPrices);  
    }  
} 

级别5

试着将策略模式和简单工厂模式相结合。

//改造后的CashContext  
public class CashContext  
{  
    CashSuper cashSuper;  
    public CashContext(CashSuper cashSuper)  
    {  
        this.cashSuper = cashSuper;  
    }     
    public CashContext(String type)  
    {  
        if ("正常收费".equals(type))  
        {  
            cashSuper = new CashNormal();  
        }  
        else if ("满300返100".equals(type))  
        {  
            cashSuper = new CashReturn(300, 100);  
        }  
        else if ("打8折".equals(type))  
        {  
            cashSuper = new CashRebate(0.8);  
        }  
    }  
    public double acceptCash(double money)  
    {  
        return cashSuper.acceptCash(money);  
    }  
}
//客户端代码  
public class Main  
{  
    private static double total = 0;  
    public static void main(String[] args)  
    {  
        consume("正常收费", 1, 1000);  
        consume("满300返100", 1, 1000);  
        consume("打8折", 1, 1000);  
        System.out.println("总计:" + total);  
    }  
    public static void consume(String type, int num, double price)  
    {  
        CashContext cashContext = new CashContext(type);  
        double totalPrices = cashContext.acceptCash(num * price);  
        total += totalPrices;  
        System.out.println("单价:" + price + " 数量:" + num + "合计:" + totalPrices);  
    }  
}  

简单工厂模式需要让客户端认识两个类,CashSuper和CashFactory,而策略模式与简单工厂模式结合的用法,客户端就只需要认识一个类CashContext。耦合度更加降低。我们在客户端实例化的是CashContext的对象,调用的是CashContext的方法,这使得具体的收费算法彻底地与客户端分离。连算法的父类CashSuper都不让客户端认识了。相当于创建了一个句柄类。看到这里可能会有点糊涂了,策略模式和简单工厂模式有什么区别呢?我们举一个简单的例子:

工厂模式:有一天你决定去吃披萨,一看菜单,哦,种类很多呀,你就点了个培根披萨,过了二十分钟,你的披萨就来了就可以吃到了。但这个披萨是怎么做的,到底面粉放了多少,培根放了多少,佐料放了多少,有多少到工序,你是不需要管的,你需要的是一个美味培根披萨。

策略模式:同样还是在披萨店,你要一个培根披萨,老板说想吃自己去做吧。原料有培根、面粉、佐料。工序有1、2、3工序,你自己去做吧。然后你就需要自己去做,到底放多少培根,放多少面粉,放多少佐料,这都你自己来决定,工序1、2、3,你是怎么实现的,都你自己决定。最后你得到了披萨。

总结一下:工厂类的使用者需要不是自己创建的对象,策略模式中Context类的使用者需要的是自己创建的对象。

你可能感兴趣的:(大话设计模式-策略模式)