前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >透过源码学习设计模式6—策略模式与Comparator

透过源码学习设计模式6—策略模式与Comparator

作者头像
java达人
发布2019-09-24 14:38:38
1.1K0
发布2019-09-24 14:38:38
举报
文章被收录于专栏:java达人java达人

简介:

定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户端。它首先定义不同的算法策略,然后客户端把算法策略作为它的一个参数。使用这种模式的一个不错的例子是Collection.sort()方法了,它使用Comparator对象作为参数。根据Comparator接口不同实现,对象会被不同的方法排序。

角色:

环境(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;

抽象策略角色(Strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现

具体策略角色(ConcreteStrategy):实现了抽象策略定义的接口,提供具体的算法实现。

原则:

1、找出应用中可能需要变化之处,把他们独立出来。

2、针对接口编程,而不是针对实现

3、多用组合,少用继承

一般使用场景:

当系统能在几种算法中快速地切换,或系统中有一些类,它们仅行为不同时,或系统中存在多重条件选择语句时,可以考虑采用策略模式。

优缺点:

优点:

1、算法可以自由切换

2、避免使用多重条件判断

3、扩展性良好

缺点:

策略类数量增多,所有的策略类都需要对外暴露(不过可以通过其他如工厂方法模式修复这个缺陷)

JDK示例:

java.util.Collections方法:

代码语言:javascript
复制
sort(List<T> list, Comparator<? super T> c)

参数:

list - 要排序的列表。

c - 确定列表顺序的比较器。null 值指示应该使用元素的 自然顺序。

根据指定Comparator产生的顺序对指定列表进行排序。此列表内的所有元素都必须能够使用指定Comparator相互比较。sort()方法是常用的策略设计模式示例之一,它以Comparator作为参数,我们可以为Comparator接口提供不同的实现。现在,Collections.sort()方法将根据传递给它的比较器实现对象排序。比如根据体重或大小来对Employee进行排序,您可以简单地创建一个Comparator来实现。

我们先来看下可与之对比的Comparable接口, 它为类的对象定义了默认顺序。这种默认顺序也称为对象的自然顺序。

代码语言:javascript
复制
class Employee implements Comparable<Employee> { 

    private int id; 

    private String name; 

    private double salary; 

    private LocalDate joiningDate; 


    public Employee(int id, String name, double salary, LocalDate joiningDate) { 

        this.id = id; 

        this.name = name; 

        this.salary = salary; 

        this.joiningDate = joiningDate; 

    } 


    public int getId() { 

        return id; 

    } 


    public void setId(int id) { 

        this.id = id; 

    } 


    public String getName() { 

        return name; 

    } 


    public void setName(String name) { 

        this.name = name; 

    } 



    public double getSalary() { 

        return salary; 

    } 



    public void setSalary(double salary) { 

        this.salary = salary; 

    } 


    public LocalDate getJoiningDate() { 

        return joiningDate; 

    } 


    public void setJoiningDate(LocalDate joiningDate) { 

        this.joiningDate = joiningDate; 

    } 



    // 根据ID进行比较

    /**

     \* @param   anotherEmployee - The Employee to be compared.

     \* @return  A negative integer, zero, or a positive integer as this employee

     \*          is less than, equal to, or greater than the supplied employee object.

    */ 

    @Override 

    public int compareTo(Employee anotherEmployee) { 

        return this.getId() - anotherEmployee.getId(); 

    } 


    // Two employees are equal if their IDs are equal

    @Override 

    public boolean equals(Object o) { 

        if (this == o) return true; 

        if (o == null || getClass() != o.getClass()) return false; 

        Employee employee = (Employee) o; 

        return id == employee.id; 

    } 


    @Override 

    public int hashCode() { 

        return Objects.hash(id); 

    } 


    @Override 

    public String toString() { 

        return "Employee{" + 

                "id=" + id + 

                ", name='" + name + '\'' + 

                ", salary=" + salary + 

                ", joiningDate=" + joiningDate + 

                '}'; 

    } 

}

但是,如果您因为某个需求更改默认顺序呢?例如,如果您想根据前面示例中的Employee对象的名称而不是id对其进行排序,该怎么办?

你不能更改compareTo()函数的实现,因为不单单是你那块的特定需求, 它会影响所有地方的顺序。

此外,如果您正在处理预定义的Java类或在第三方库中定义的类,则无法更改默认顺序。例如,字符串对象的默认顺序是按字母顺序排列。但是如果你想根据它们的长度来排序呢?

对于这种情况,Java提供的正是Comparator接口。您可以定义一个Comparator并将其传递给像Collections.sort() 或 Arrays.sort()的排序函数。根据Comparator定义的顺序对对象排序。

代码语言:javascript
复制
public interface Comparator<T> { 

    int compare(T o1, T o2); 

} 



public class ComparatorExample { 

    public static void main(String[] args) { 

        List<Employee> employees = new ArrayList<>(); 


        employees.add(new Employee(1010, "Rajeev", 100000.00, LocalDate.of(2010, 7, 10))); 

        employees.add(new Employee(1004, "Chris", 95000.50, LocalDate.of(2017, 3, 19))); 

        employees.add(new Employee(1015, "David", 134000.00, LocalDate.of(2017, 9, 28))); 

        employees.add(new Employee(1009, "Steve", 100000.00, LocalDate.of(2016, 5, 18))); 



        System.out.println("Employees : " + employees); 


        // 根据名称排序

        Comparator<Employee> employeeNameComparator = new Comparator<Employee>() { 

            @Override 

            public int compare(Employee e1, Employee e2) { 

                return e1.getName().compareTo(e2.getName()); 

            } 

        }; 

        /*

        上面的Comparator可以用如下的lambda表达式写 =>

        employeeNameComparator = (e1, e2) -> e1.getName().compareTo(e2.getName());

        Java 8 Comparator默认方法甚至可以写的更简单

        employeeNameComparator = [Comparator.comparing(Employee::getName](http://Comparator.comparing(Employee::getName))

        */ 

        Collections.sort(employees, employeeNameComparator); 

        System.out.println("\nEmployees (Sorted by Name) : " + employees); 

        // 根据收入排序

        Comparator<Employee> employeeSalaryComparator = new Comparator<Employee>() { 

            @Override 

            public int compare(Employee e1, Employee e2) { 

                if(e1.getSalary() < e2.getSalary()) { 

                    return -1; 

                } else if (e1.getSalary() > e2.getSalary()) { 

                    return 1; 

                } else { 

                    return 0; 

                } 

            } 

        }; 


        Collections.sort(employees, employeeSalaryComparator); 

        System.out.println("\nEmployees (Sorted by Salary) : " + employees); 


        //根据入职时间排序

        Comparator<Employee> employeeJoiningDateComparator = new Comparator<Employee>() { 

            @Override 

            public int compare(Employee e1, Employee e2) { 

                return e1.getJoiningDate().compareTo(e2.getJoiningDate()); 

            } 

        }; 


        Collections.sort(employees, employeeJoiningDateComparator); 

        System.out.println("\nEmployees (Sorted by JoiningDate) : " + employees); 

    } 

}

与状态模式区别

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档