软件设计的原则
1: 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起
2:针对接口编程,而不是针对实现编程
策略模式的定义
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
通俗的将就是使用动态注入的对象或实现来动态替换某种具体行为.
使用场景
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别
2.需要安全的封装多种同一类型的操作
3.出现同一抽象类有多个子类,而又需要使用条件语句来选择 具体子类时
关键点
一个抽象的策略或算法
一个或多个具体的抽象实现
一个操作策略或算法的上下文,持有抽象,可以动态注入具体实现
策略模式实例结构
1:环境对象
2:抽象策略角色:给出所有具体策略角色使用的接口
3:具体策略角色:抽象策略角色的实现类
经典案例
设计售卖各类图书的购物车系统
思路:由于各类图书的折扣价不一致,而且可能后续还会有其他的折扣算法出现,所有为了系统的高扩展和高维护性,使用策略模式来进行实现
UML图
策略抽象类
abstract public class DiscountStrategy { private int price = 0; private int copies = 0; /** * 策略方法 * @return */ public abstract int calculateDiscount(); /** * 初始化值 * @param price * @param copies */ public DiscountStrategy(int price, int copies) { this.price = price; this.copies = copies; }
策略具体实现类
public class FlatRateStrategy extends DiscountStrategy { private int price; private int copies; /** * 初始化值 * * @param price * @param copies */ public FlatRateStrategy(int price, int copies) { super(price, copies); this.price = price; this.copies = copies; } @Override public int calculateDiscount() { return 0; } }
ublic class NoDiscountStrategy extends DiscountStrategy { private int price; private int copies; private int amount; /** * 初始化值 * * @param price * @param copies */ public NoDiscountStrategy(int price, int copies) { super(price, copies); this.price = price; this.copies = copies; } /** * 策略的具体实现 * @return */ @Override public int calculateDiscount() { return copies * amount; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; }
public class PercentageStrategy extends DiscountStrategy { private int precent; private int price; private int copies; /** * 初始化值 * * @param price * @param copies */ public PercentageStrategy(int price, int copies) { super(price, copies); this.price = price; this.copies = copies; } /** * 策略的具体实现 * @return */ @Override public int calculateDiscount() { return copies*price*precent; } public int getPrecent() { return precent; } public void setPrecent(int precent) { this.precent = precent; } }
环境对象类
public class BookContext { /*私有化构造器*/ private BookContext() { } /*策略对象*/ private DiscountStrategy discountStrategy; /** * 提供对外的方法 * @return */ public int calculateDiscount(){ return discountStrategy.calculateDiscount(); } public static BookContext getInstance() { return BookContextLoadHolder.INSTANCE; } /** * 内部类 提供独有的实例 */ public static final class BookContextLoadHolder { private static final BookContext INSTANCE = new BookContext(); } public DiscountStrategy getDiscountStrategy() { return discountStrategy; } public void setDiscountStrategy(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } }
测试类
public class TestStrategy { public static void main(String[] args) { BookContext context = BookContext.getInstance(); context.setDiscountStrategy(new FlatRateStrategy(100, 10)); System.out.println("FlatRateStategy---->"+context.calculateDiscount()); NoDiscountStrategy noDiscountStrategy = new NoDiscountStrategy(100, 10); noDiscountStrategy.setAmount(10); context.setDiscountStrategy(noDiscountStrategy); System.out.println("NoDiscountStrategy------>"+context.calculateDiscount()); PercentageStrategy percentageStrategy = new PercentageStrategy(100, 10); percentageStrategy.setPrecent(10); context.setDiscountStrategy(percentageStrategy); System.out.println("percentageStrategy------>"+context.calculateDiscount()); }
这样我们就实现了根据业务的需求来灵活的变更折扣的计算方式
什么情况下使用策略模式
1:系统里面有许多类的区别仅在于它们的行为。
2:系统需要动态地在几种算法中选择一种
3: 当系统使用的算法需要保密的时候
4: 一个对象有很多的行为
策略模式的优点和缺点
优点
1: 提供了管理相关算法族的办法
2: 提供了可以替换继承关系的办法
3: 可以避免多重条件判断语句
缺点
1: 只适用于客户端知道所有的算法或行为的时候
2: 造成很多的策略类