gof23——策略模式


策略模式(Strategy Pattern)是指定义了算法家族并分别封装恰里,让它们之间可以相互替换,此模式使得算法的变化不会影响使用算法的用户

一、策略模式的使用场景

  • 系统中有很多类,而他们的区别仅仅在于行为的不同
  • 一个系统需要动态地再几种算法中选择一种

二、策略模式的应用场景

网上购物现在已经是我们生活的常态,在网上购物时商家为了提高商品销量通常会举行一些促销活动,这里模拟促销优惠活动,来展示策略模式的应用

首先创建一个促销策略的接口:

/**
 * @author xxbb
 */
public interface PromotionStrategy {
    /**
     * 优惠策略
     */
    void doPromote();
}

创建具体的优惠策略,优惠券优惠策略类CouponStrategy、返现促销策略类CashbackStrategy、拼团优惠策略类GroupByStrategy和无优惠策略类EmptyStrategy。

/**
 * @author xxbb
 */
public class CouponStrategy implements PromotionStrategy {
    @Override
    public void doPromote() {
        System.out.println("领取优惠券,满100-39");
    }
}
public class CashbackStrategy implements PromotionStrategy{
    @Override
    public void doPromote() {
        System.out.println("返现促销,满100返现39,次日转回付款账号");
    }
}
public class GroupBuyStrategy implements PromotionStrategy{
    @Override
    public void doPromote() {
        System.out.println("拼团优惠,满5人成团,享受8折优惠");
    }
}
public class EmptyStrategy implements PromotionStrategy {
    @Override
    public void doPromote() {
        System.out.println("无促销策略");
    }
}

编写促销活动方案类,用于执行策略

public class PromotionActivity {
    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy){
        this.promotionStrategy=promotionStrategy;
    }
    public void executor(){
        promotionStrategy.doPromote();
    }
}

测试代码:

public class Client {
    public static void main(String[] args) {
        PromotionActivity couponActivity=new PromotionActivity(new CouponStrategy());
        PromotionActivity cashbackActivity=new PromotionActivity(new CashbackStrategy());
        couponActivity.executor();
        cashbackActivity.executor();
    }
}

可以看到活动方案类根据传入的策略类的不同执行了不同的策略,这里很好的体现了面向对象的三大特征之一——多态。

然后我们再结合简单工厂模式优化下代码,使用户只需要关系选择的策略,而不需要了解策略的创建过程。

public class PromotionStrategyFactory {
    interface PromotionKey{
        String COUPON="COUPON";
        String CASHBACK="CASHBACK";
        String GROUP_BUY="GROUP_BUY";
        String EMPTY="EMPTY";
    }
    private static Map<String,PromotionStrategy> promotionStrategyMap=new HashMap<>(10);

    static{
        promotionStrategyMap.put(PromotionKey.COUPON,new CouponStrategy());
        promotionStrategyMap.put(PromotionKey.CASHBACK,new CashbackStrategy());
        promotionStrategyMap.put(PromotionKey.GROUP_BUY,new GroupBuyStrategy());
    }
    private static final PromotionStrategy NON_PROMOTION=new EmptyStrategy();
    private PromotionStrategyFactory(){}

    public static PromotionStrategy getPromotionStrategy(String promotionKey){
        PromotionStrategy promotionStrategy=promotionStrategyMap.get(promotionKey);
        return promotionStrategy==null?NON_PROMOTION:promotionStrategy;
    }
}

测试类:

public class Client {
    public static void main(String[] args) {
        String promotionKey= "COUPON";
        PromotionActivity promotionActivity=new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
        promotionActivity.executor();

    }
}

三、策略模式在源码中的体现

在JDK容器中我们有一个常用的比较器——Comparetor接口,其中的compare方法就是策略模式的抽象实现

public interface Comparator<T> {
	int compare(T o1, T o2);
}

Comparetor接口下有非常多的实现类。

image-20200704152801860

我们经常会把Comparetor接口作为传入参数实现排序策略,例如Arrays的parallelSort()

public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
    if (cmp == null)
        cmp = NaturalOrder.INSTANCE;
    int n = a.length, p, g;
    if (n <= MIN_ARRAY_SORT_GRAN ||
        (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
        TimSort.sort(a, 0, n, cmp, null, 0, 0);
    else
        new ArraysParallelSortHelpers.FJObject.Sorter<T>
            (null, a,
             (T[])Array.newInstance(a.getClass().getComponentType(), n),
             0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
             MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
}

还有TreeMap在实例化时能自定义排序策略

public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}

在Spring源码中的Resource接口也采用策略模式,不同的资源会采用不同的加载策略实现类。

在Spring的初始化时也才采用了策略模式,提供了一个InstantiationStrategy接口,下面提供两种策略实现类SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy.

image-20200704154643934

四、策略模式的优缺点

策略模式的优点:

  • 符合开闭原则
  • 体现多态特性
  • 可以避免使用多重条件语句如if,switch来执行具体算法
  • 可以提高算法的保密性和安全性

策略模式的缺点:

  • 用户必须了解所有的策略,并自行决定使用哪一种策略类
  • 当代码中的策略非常多时,代码维护的难度增加

五、委派模式

委派模式(Delegate Pattern)不属于GoF23种设计模式。委派模式的基本作用就是负责人物的调用和分配,跟代理模式很香,可以看作一种特殊情况下的静态的全权代理,但代理模式注重过程,委派模式注重结果。这里通过老板下达指令,员工执行指令来展示委派模式

public interface IEmployee {
     void working(String command);
}
public class EmployeeB implements IEmployee{
    @Override
    public void working(String command) {
        System.out.println("我是员工B,正在执行"+command+"工作");
    }
}
public class EmployeeA implements IEmployee{
    @Override
    public void working(String command) {
        System.out.println("我是员工A,正在执行"+command+"工作");
    }
}
public class Leader implements IEmployee{

    private Map<String,IEmployee> employeeMap=new HashMap<>(5);

    public Leader(){
        employeeMap.put("登录",new EmployeeA());
        employeeMap.put("加密",new EmployeeB());
    }

    /**
     * 经理委派员工干活
     * @param command 命令
     */
    @Override
    public void working(String command) {
        employeeMap.get(command).working(command);
    }
}
public class Boss {
    public void command(String command,Leader leader){
        leader.working(command);
    }
}
public class TestMain {

    public static void main(String[] args) {
        //代理模式注重过程,委派模式注重结果
        //策略模式注重可扩展性(外部可扩展性),委派模式注重内部的灵活性和可重复性
        //委派模式的核心是分发,调度,派遣,委派模式是静态代理模式和策略模式的一种特殊组合
        //分发:Boss将“登录”指令分发给Leader
        //调度:Leader根据登录指令调度具体的EmployeeA
        //派遣:EmployeeA被Leader派遣执行working方法
        new Boss().command("登录",new Leader());
    }
}

可以看到在Boss处我们将“登录”作为策略分发给Leader,Leader可以看作是Boss的代理,为Boss执行任务。而在Leader中根据Boss给出的策略选择对应的员工执行命令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值