java设计模式之策略模式

定义

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

我的个人理解

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

编码实现

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

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的方法。跟之前的购物付款的例子很相似。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值