【Clean Smell】Why ‘lambda'?

最近在bibi看了一个视频,Up主一步步引出Lambda的方式看着很精彩,本文做个分享。

 

【背景】

如下,部门有十名员工,过滤"35岁以上","薪资高于5000" 的员工,怎么做呢?

public class Employee {
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 薪水
     */
    private Double salary;
    /**
     * 状态
     */
    private Status status;

    public Employee(String name, Integer age, Double salary){
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    
    //getter and setter ignore
}
static List employees = Arrays.asList(
    new Employee("张一",26,1226.66),
    new Employee("王二",77,3456.66),
    new Employee("张三",16,226.66),
    new Employee("李四",31,666.66),
    new Employee("王五",25,623.66),
    new Employee("赵六",40,546.66),
    new Employee("陈七",33,666.66),
    new Employee("马八",55,999.66),
    new Employee("刘九",29,666.66),
    new Employee("周十",37,768.66)
);

 

【设计】

第一版:常规循环

1.方法过滤

class ForFilter{
    //过滤年龄
    public static List filterEmployeesAge(List list){
        List emps = new ArrayList<>();

        for(Employee emp : list){
        if(emp.getAge() >= 35){
            emps.add(emp);
        }
        }
        return emps;
    }

    //过滤薪资
    public static List filterEmployeesSalary(List list){
        List emps = new ArrayList<>();

        for(Employee emp : list){
        if(emp.getSalary() >= 5000){
            emps.add(emp);
        }
        }
        return emps;
    }
}

2.调用:

public static void main(String[] args) {
    //遍历过滤 年龄
    List list = filterEmployeesAge(employees);
    for(Employee employee : list){
        System.out.println(employee);
    }
    //遍历过滤 薪资
    List list1 = filterEmployeesSalary(employees);
    for(Employee employee : list1){
        System.out.println(employee);
    }
}

分析:

1.优点:无

2.缺点:新增过滤条件,需添加新的"filterBy"方法,该方法代码重复度高大80%。

 

第二版:策略模式

1.策略接口

public interface MyPredicate {
    /**
     * 过滤条件
     */ 
    public boolean test(T t);
}

2.策略类,实现MyPredicate接口

public class FilterEmployeeByAge implements MyPredicate {
    /**
     * 年龄大于35岁
     */
    @Override
    public boolean test(Employee t) {
        return t.getAge() >= 35;
    }
}

public class FilterEmployeeBySalary implements MyPredicate {
    /**
     * 薪资大于5000
     */
    @Override
    public boolean test(Employee t) {
        return t.getSalary() > 5000;
    }
}

3.调用

public static void main(String[] args) {
    //策略模式 - 过滤年龄
    List list2 = filterEmpByStrategy(employees, new FilterEmployeeByAge());
    for(Employee employee : list2){
        System.out.println(employee);
    }

    //策略模式 - 过滤薪资
    List list3 = filterEmpByStrategy(employees, new FilterEmployeeBySalary());
    for(Employee employee : list3){
        System.out.println(employee);
    }
}

/**
 * 根据策略过滤
 */
public static List filterEmpByStrategy(List list, MyPredicate mp){
    List emps = new ArrayList<>();

    for(Employee employee : list){
        if(mp.test(employee)){
            emps.add(employee);
        }
    }    
    return emps;
}

策略模式,分析:

1.优点:新增需求时,虽新增接口实现类,但利用多态,重复代码大量减少。

2.缺点:虽减少了重复代码,新增需求时,接口实现类略显臃肿

 

第三版:策略+匿名内部类

1.策略接口

public interface MyPredicate {
    /**
     * 过滤条件
     */
    public boolean test(T t);
    
}

2.调用

public static void main(String[] args) {
    //调用过滤器时,以匿名内部类形式,实现过滤接口
    List list4 = filterEmpByStrategy(employees, new MyPredicate() {
        @Override
        public boolean test(Employee employee) {
            return employee.getSalary() < 5000;
        }
    });
    for(Employee employee : list4){
        System.out.println(employee);
    }
}

/**
 * 过滤器
 */
public static List filterEmpByStrategy(List list, MyPredicate mp){
    List emps = new ArrayList<>();

    for(Employee employee : list){
        if(mp.test(employee)){
            emps.add(employee);
        }
    }
    return emps;
}

分析:

1.优点: 相比“策略模式”,去掉接口实现类

2.缺点:匿名内部类编码时,又产生了部分冗余代码

 

第四版:Lambda

1.保留“MyPredicate”过滤接口、“filterEmpByStrategy”过滤器

2.调用

public static void main(String[] args) {
    List list = filterEmpByStrategy(employees, (e) -> e.getSalary() <= 5000);
    list.forEach(System.out::println);
}

分析:

1.优点:几乎零重复;只定义接口,无需实现类 或 匿名实现类。

2.思考:fiterEmpStrategy() 及MyPredicate接口,是否可简化?

 

第五版:Stream Api

public static void main(String[] args) {
    employees.stream()
        .filter((e) -> e.getSalary() <= 5000)
        .limit(2)
        .forEach(System.out::println);
}

分析:

1.优点:简洁;无需接口、实现类、过滤器等

2.缺点:无

 

【总结】

刚入门的人把编程当理科,学习中的人当工科,但最终编程是文科,就像写文章画画,是作者思想的呈现。

你可能感兴趣的:(lambda)