【Java设计模式】浅谈设计模式(三)之策略模式

一、策略模式概述

       首先给出一个听起来官方的定义:策略模式将可变的部分从程序中抽象分离成算法接口,在该算法接口下分别封装一系列算法实现。

       举一个实际的例子来说明:我们在网上购物支付的时候,会发现电商平台一般会提供各种各样的支付方式选择,用户只需要选择其中之一便可进行支付操作。

       可以发现,上述例子中的支付算法便是抽象出来的算法接口,在这个接口里面封装了各种支付算法的实现,比如工商银行支付、支付宝支付……等等。这样,当需要添加一种新的支付方式时,只需要在接口下提供一个新的算法实现即可,客户端可以独立于这种改变之外。可以看到策略模式对于新增的需求具有弹性的支持。


二、以一个实例说明策略模式的实现

       我们用文章开篇的用户网购支付的例子来说明策略模式。首先有如下基本代码,包括一个抽象顾客基类Consumer.java和两个顾客类。

Consumer.java:

package com.bebdong.Strategy_pattern;

/**
 * @author Administrator
 * 用户的抽象类
 */
public abstract class Consumer {

    public void login(){
        System.out.println("用户登录");
    }

    public void buy(){
        System.out.println("用户购买");
    }

    public abstract void display();
}

ConsumerA.java:

package com.bebdong.Strategy_pattern;

public class ConsumerA extends Consumer {

    public ConsumerA() {
        super();
    }

    @Override
    public void display() {
        System.out.println("我是顾客类型A……");
    }

}

ConsumerB.java:

package com.bebdong.Strategy_pattern;

public class ConsumerB extends Consumer {

    public ConsumerB() {
        super();
    }

    @Override
    public void display() {
        System.out.println("我是顾客类型B……");

    }

}

       OK,有了上面的基础,我们来讨论如何实现支付这样的一个行为:

  1. 继承:类似buy()方法和login()方法,在抽象基类中实现一个pay()来实现支付。虽然这样简(cu)单(bao),但是也具有相当的缺点:那就是不够灵活。因为不同的顾客会偏好不同的支付方式。
  2. 抽象方法(多态):类似dispaly()方法,在抽象基类中添加一个抽象方法pay(),强迫子类来实现它。这样一来,好像解决了第一个方案的问题,但是我们仔细思考可以发现问题:对未来需求的弹性不高,一个用户可能拥有几种支付方式,而且不利于代码维护。试想一下,如果某天我们需要改变这个支付方法的名称(可能不恰当,只是举个例子说明),那么每一个顾客类型的代码都需要修改。
  3. 组合。

       经过上面的分析,我们说继承是面向对象编程中代码重用的一门利器,但有时候它也有不可避免的缺点。在《Effective Java》一书中有这样能一句话:Favor composition over inheritance. 意思大致为组合优于继承。那么什么是组合呢?

       在类中增加一个私有域,引用另一个已有类的实例,通过调用引用实例的方法从而获得某种,这种设计被称之为组合(复合)。

       利用组合和策略模式的思想,我们得出了如下方案:添加一个支付的接口PayWay,然后添加不同的支付方式类来实现这样一个接口。

PayWay.java(将共性抽象为接口)

package com.bebdong.Strategy_pattern;

public interface PayWay {

    public void performPay();
}

Consumer.java:做相应修改(对象类拥有策略接口)

package com.bebdong.Strategy_pattern;

/**
 * @author Administrator
 * 用户的抽象类
 */
public abstract class Consumer {

    public void login(){
        System.out.println("用户登录");
    }

    public void buy(){
        System.out.println("用户购买");
    }

    public abstract void display();

    /*以下部分为新增代码*/
    private PayWay payWay;
    public void setPayWay(PayWay payWay){
        this.payWay=payWay;
    }

    public void pay(){
        payWay.performPay();
    }
}

下面我们封装两种支付方式以具体说明:(添加策略实现类)

AliPay.java:

package com.bebdong.Strategy_pattern;

public class AliPay implements PayWay {

    @Override
    public void performPay() {
        System.out.println("用支付宝支付");
    }

}

ICBCPay.java:

package com.bebdong.Strategy_pattern;

public class ICBCPay implements PayWay {

    @Override
    public void performPay() {
        System.out.println("用工行支付");

    }

}

假设用户类型A使用支付宝支付,而用户类型B使用工行支付(为不同对象注入不同的策略)
下面我们用ConsumerTest.java来模拟这个过程:

package com.bebdong.Strategy_pattern;

public class ConsumerTest {

    public static void main(String[] args) {
        System.out.println("====模拟开始====");

        Consumer consumerA=new ConsumerA();
        Consumer consumerB=new ConsumerB();
        consumerA.setPayWay(new AliPay());
        consumerB.setPayWay(new ICBCPay());

        System.out.println(">>>>这里是用户A<<<<");
        consumerA.display();
        consumerA.login();
        consumerA.buy();
        consumerA.pay();

        System.out.println(">>>>这里是用户B<<<<");
        consumerB.display();
        consumerB.login();
        consumerB.buy();
        consumerB.pay();

        System.out.println("====模拟结束====");

    }

}

运行可以得到如下结果:
这里写图片描述

       这样一来,当需要增加新的支付方式时,只需要继承PayWay接口并提供具体实现即可。所有顾客都可以选择使用这种方式进行支付。


三、总结

       从上面的实例中,我们可以概括出策略模式的设计原则

  • 1、将应用中不变的部分抽象为接口,而变得部分交由具体实现;
  • 2、面向接口编程,而不是面向实现编程。接口规定了实现框架,然后通过多态实现了多样性;
  • 3、组合优先继承。

       >>>>>>>>>策略模式的实现要点<<<<<<<<<

  • 1、通过分析,分理处策略接口;
  • 2、为接口提供实现类;
  • 3、对象“拥有”一个Strategy,通过它来实现具体的行为;
    这里写图片描述

  • 4、客户程序中选择/组装正确的Strategy实现。
    这里写图片描述

       >>>>>>>>>策略模式的优点<<<<<<<<<

  • 1、策略模式往往和组合密不可分,架构具有相当的灵活性;
  • 2、负有弹性,能较好的应对需求变化(开-闭);
  • 3、拥有更好的代码复用性
  • 4、消除了相当多的条件语句(不需要判断要执行哪种行为),易于维护。

       >>>>>>>>>策略模式的缺点<<<<<<<<<

  • 1、可以看到需要为每一个类(对象)注入策略(要点4),故而客户程序需要了解策略的实现细节。
  • 2、随着时间推移,策略实现类将显著增加。

       >>>>>>>>>策略模式的使用场景<<<<<<<<<

  1. 许多相关类仅仅是行为差异,将差异共性抽象为策略接口;
  2. 运行时选取不同的算法变体。如不同的支付算法,运行时只会运行一种支付算法。
  3. 程序含有相当的条件判断语句if……else……。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值