java设计模式之策略模式

来源:互联网 发布:注册淘宝用什么名字好 编辑:程序博客网 时间:2024/05/20 05:08

定义

策略模式就是定义一个算法族,分别封装起来,让他们之前可以互相替换。此模式让算法的变化独立于使用算法的客户。

我的个人理解

定义中的解释可能有些官方,用大白话说,就是为了解决一个问题,定义一组方法类,然后呢,具体要用哪一种方法解决问题,让用户自己去决定。举个现实中的例子,我们去超市买东西,我们就是客户,我们买好东西要付钱了,我们会有很多种方式:支付宝支付,现金支付,微信支付等。具体用哪一种方式来付钱,完全取决于我们自身(客户)。策略模式实际上关心的不是算法的实现,而且提供一种方式管理这些算法。下面以这个购物付款的例子进行编码实现一个简单的策略模式。

编码实现

首先,抽象出一个付款的接口。在设计模式中,很重要的一个设计原则就是面向接口编程(这里的面向接口,是广义的,即面向超类进行编程,也就是说也包含抽象类)。这个付款的接口就是我们客户要使用的付款对象的超类。

public interface PayMethod {    void pay();}

其次,定义出我们付款的三种类型,都是该接口的实现类:
public class WechatPay implements PayMethod {    @Override    public void pay() {        System.out.println("我使用微信支付");    }}

public class CashPay implements PayMethod {    @Override    public void pay() {        System.out.println("我使用现金支付");    }}

public class AliPay implements PayMethod {    @Override    public void pay() {        System.out.println("我使用支付宝来支付");    }}
现在我们可以定义客户对象了,就是要使用付款方式的对象。我们将付款方式作为客户对象的一个属性,并且以构造方法的形式初始化。
public class Customer {    private PayMethod payMethod;    public Customer(PayMethod payMethod) {        this.payMethod = payMethod;    }    public void buyGoods() {        this.payMethod.pay();        System.out.println("我东西买好了");    }}
从代码中我们可以看出,购物的方法buyGoods()实际上是用传入的PayMethod的付款方式进行付款的,由于三种付款方式都实现了付款的接口,也就是都有一个付款的方法。所以这里利用了多态的优势。
现在可以写测试类来测试了,也很简单:
public class Main {    public static void main(String[] args) {        PayMethod payMethod = new WechatPay();        Customer customer = new Customer(payMethod);        customer.buyGoods();    }}
我们可以看到,先定义了一个微信的付款方式,再传进实例化的客户对象中,接着我们调用购买buyGoods()方法的时候,实际上用的就是微信的付款方式。至此,一个策略模式的demo已经实现了。

思考策略模式的优缺点

优点:我们从上例中可以看出,策略模式的一个优点,就是将算法统一的管理起来了。这些算法之间相互平等,并且都实现一个接口,包含相同的方法。这使得客户使用的时候可以随意的根据自己的需要切换。

缺点:客户如果想要随意的切换策略,就要知道所有的策略类,不然无法根据自己的需要来确定最终的策略;其次,所有的策略类都是以类的形式存在的,所以如果某一个模式包含的策略比较多时候,会造成类的数量很多,不利于维护。

jdk中用到的策略模式举例

jdk中的比较器的实现,用的实际上就是策略模式,我们在针对一个集合排序的时候,可以传入一个比较器Comparator进行自定义的比较策略实现。如下例:

定义一个Student学生类(重写toString是为了方便打印结果观看):

public class Student {    private String name;    private Integer age;    private String info;    public Student() {    }    public Student(String name, Integer age, String info) {        this.name = name;        this.age = age;        this.info = info;    }    @Override    public String toString() {        return "Student{" +                "name='" + name + '\'' +                ", age=" + age +                ", info='" + info + '\'' +                '}';    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public String getInfo() {        return info;    }    public void setInfo(String info) {        this.info = info;    }}
先定义一个年龄比较器,根据学生的年龄进行升序排列:

public class AgeComparator implements Comparator<Student> {    @Override    public int compare(Student o1, Student o2) {        return o1.getAge()-o2.getAge();    }}
再定义一个姓名比较器,根据学生的姓名进行排序:
public class NameComparator implements Comparator<Student> {    @Override    public int compare(Student o1, Student o2) {        return o1.getName().compareTo(o2.getName());    }}
接着编写测试类测试,打印出根据年龄排序和根据姓名排序的集合的值:

public class TestStrategy {    public static void main(String[] args) {        List<Student> studentList = new ArrayList<Student>();        studentList.add(new Student("zhangsan", 12, "张三"));        studentList.add(new Student("lisi", 11, "李四"));        studentList.add(new Student("wangwu", 13, "王五"));        studentList.add(new Student("zhaoliu", 14, "赵六"));        studentList.add(new Student("tianqi", 15, "田七"));        Collections.sort(studentList, new AgeComparator());        System.out.println("根据年龄比较==>" + studentList.toString());        Collections.sort(studentList, new NameComparator());        System.out.println("根据姓名比较==>" + studentList.toString());    }}
打印结果:


我们可以看到,根据年龄比较的结果,集合按照年龄的大小进行了升序排列;根据姓名比较的结果,集合按照姓名的首字母的码表顺序进行了排序。

上例中的两个比较器,都实现了Comparator的接口,都实现了compare的方法。跟之前的购物付款的例子很相似。

原创粉丝点击