【问题标题】:Refactoring code to be Generics and functional interface将代码重构为泛型和功能接口
【发布时间】:2017-04-06 13:40:41
【问题描述】:

我有两个接口,一个可以用来通过 Key 和 Value 查找一些统计信息,另一个用于访问一个对象并对其进行迭代,第一个具有以下方法:

public interface Statistic {

    public String getKey();

    public Object getValue();

    public String getDetails();
}

这是它的实现:

public class Collector implements Statistic {

    private String key;
    private int val;

    public Collector(String key, int val) {
        this.key = key;
        this.val = val;
    }

    public void setValue(int val) {
        this.val = val;
    }

    @Override
    public String getKey() {
        return key;
    }

    @Override
    public Integer getValue() {
        return val;
    }

    @Override
    public String getDetails() {
        return null;
    }
}

另一个有以下内容:

public interface StatisticsCollector<T extends Object, S extends Statistic> {

    public String getName();

    public void visit(T object);

    public Iterator<S> calculatedStatistics();
}

这是它的实现:

public class CalculateFromObject<K, V> implements StatisticsCollector<Object, Collector> {

    EmployeeValidator empValidator = new EmployeeValidator();
    StringValidator strValidator = new StringValidator();

    @Override
    public String getName() {
        return null;
    }

    @Override
    public void visit(Object object) {
        if (object instanceof String) {
            String str = object.toString();

            int upperCaseCount = strValidator.upperCaseFreq(str);
            strValidator.set.add(new Collector("Upper Case Letters: ", upperCaseCount));
            int lowerCaseCount = strValidator.lowerCaseFreq(str);
            strValidator.set.add(new Collector("Lower Case Letters: ", lowerCaseCount));
            int digitsCount = strValidator.digitFreq(str);
            strValidator.set.add(new Collector("Digits Count: ", digitsCount));
            int wordCount = strValidator.wordFreq(str);
            strValidator.set.add(new Collector("Words Count: ", wordCount));
            int nonWordCount = strValidator.nonWordFreq(str);
            strValidator.set.add(new Collector("Non Word Count: ", nonWordCount));

        } else if (object instanceof Employee) {

            Employee emp = (Employee) object;
            empValidator.salaryValidator(emp);
            empValidator.birthDateValidator(emp);
            empValidator.birthPlaceValidator(emp);
            empValidator.resignationDateValidator(emp);
            empValidator.positionValidator(emp);
        }
    }

    @Override
    public Iterator<Collector> calculatedStatistics() {
        return empValidator.set.iterator();
    }


}

在我的包中,我有一个用于 Employee 的 bean,它具有一些属性,例如 firstName、lastName、salary 和 position 以及它们的 setter 和 getter。

我想做一些验证,比如获取薪水为 x 且出生于 1990 年的员工人数,并为这些验证做了以下课程:

public class EmployeeValidator {

    public Set<Collector> set = new HashSet<>();

    public void salaryValidator(Employee emp) {
        int count = 0;
        // each collector consist of a condition (function), key, value (always incremented)
        if (emp.getSalary() < 350) {
            set.add(new Collector("Employee with salaries less than 350JD: ", ++count));
        } else if (emp.getSalary() >= 350 && emp.getSalary() < 600) {
            set.add(new Collector("Employee with salaries between 350JD And 600JD: ", ++count));
        } else if (emp.getSalary() >= 600 && emp.getSalary() < 1200) {
            set.add(new Collector("Employee with salaries between 600JD And 1200JD ", ++count));
        } else if (emp.getSalary() >= 1200) {
            set.add(new Collector("Employee with salaries more than 1200JD: ", ++count));
        }

    }

    public void birthDateValidator(Employee emp) {
        for (Collector stats : set) {
            if (("Employees that where born in " + emp.getBirthDate().getYear() + " = ").equals(stats.getKey())) {
                count(stats);
                return;
            }
        }
        set.add(new Collector("Employees that where born in " + emp.getBirthDate().getYear() + " = ", 1));
    }

    public void birthPlaceValidator(Employee emp) {
        for (Collector stats : set) {
            if (("Employees that where born in " + emp.getBirthPlace() + " = ").equals(stats.getKey())) {
                count(stats);
                return;
            }
        }
        set.add(new Collector("Employees that where born in " + emp.getBirthPlace() + " = ", 1));
    }

    public void resignationDateValidator(Employee emp) {
        for (Collector stats : set) {
            if (("Employees that where Resignation in " + emp.getResignationDate().getYear() + " = ").equals(
                    stats.getKey())) {
                count(stats);
                return;
            }
        }
        set.add(new Collector("Employees that where Resignation in " + emp.getResignationDate().getYear() + " = ", 1));
    }

    public void positionValidator(Employee emp) {
        for (Collector stats : set) {
            if (("Employees that occupy the " + emp.getPosition() + " position = ").equals(stats.getKey())) {
                count(stats);
                return;
            }
        }
        set.add(new Collector("Employees that occupy the " + emp.getPosition() + " position = ", 1));
    }

    private void count(Collector stats) {
        int counter = stats.getValue() + 1;
        stats.setValue(counter);
    }
}

我还有另一个类来验证字符串,看看一个字符串有多少个大写字母,有多少个小写字母......等等

正如您在CalculateFromObject 类中的访问方法中看到的那样,我调用了我所有的方法来进行验证,一切正常,我得到了预期的结果,但是我的代码效率不是我想要的那样它是通用的,让它接受任何类型的对象,我做了几次尝试,但我卡住了。

我尝试编写一个名为条件的功能接口,它有一个方法可以传递条件并检查它,如下所示:

public interface Conditions {

    boolean checkCondition(Object obj);

}

那么有人可以建议将我的代码更改为通用代码并接受任何类型的对象(例如 Student)并尽可能干净的最佳方法是应用设计模式吗?

【问题讨论】:

    标签: java generics design-patterns coding-style functional-interface


    【解决方案1】:

    您的类中有很多开销,并且对POJO's(简单类)的接口存在误解。在高层次上,您应该执行以下操作:

    1)。删除接口Statistic 和类Collectors。它们只是封装数据。相反 - 创建一个带有必要字段 + getter + setter 的 POJO Employee。不要使用'key-value',给这些字段起有意义的名字:

    public class Employee
    {
        private String name;
        private int id;
        private double salary;
            ...
         public String getName() {...}
         public void setName(..) {...}
    // other getters / setters
    }
    

    根据需要创建构造函数

    2) 看起来您的 Employee 类也是多余的,请将其删除。改用新员工 3) 使用Collections 框架来存储员工实例的集合。

    `List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(.... )); `
    

    4)。使用验证方法创建接口 EmployeeValidator 并实现它:

    public interface EmployeeValidator { void validate(List<Employee> employees); }

    5) 如果你想操作一些统计数据,创建一个单独的Statistics 类,它将对员工的集合进行操作,例如

    public class Statistics {
    
        public double getAvgSalary(List<Employee> employees)
        {
            double avgSalary = 0;
            for (Employee e : employees) {
            ....
            }
        }
    }
    

    【讨论】:

    • 我不能删除接口统计和收集器,因为任务是实现它们
    • 主要思想是您在滥用接口。用类重构它并留下必要的
    • 好的,我明白你的意思了,谢谢,现在我怎样才能使它通用并使它易于为学生对象实现相同的 rxample?
    • 你能解释一下我是如何滥用接口的吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多