避免在实体中使用instanceof

时间:2016-04-09 09:30:32

标签: java oop

今天我读了this article关于避免使用instanceof的问题。 这对我来说绝对有意义。我也知道visitor pattern

假设我有以下情况:

@Entity
public abstract class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer employeeId;

    private String name;

}



@Entity
public class FullTimeEmployee extends Employee {

    protected Integer salary;

    public Integer getSalary() {
        return salary;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }
}
@Entity
public class PartTimeEmployee  extends  Employee{

    protected Float hourlyWage;

    public Float getHourlyWage() {
        return hourlyWage;
    }

    public void setHourlyWage(Float hourlyWage) {
        this.hourlyWage = hourlyWage;
    }
}

在调用这样的方法时,如何避免使用instanceof?

    public void convertEmployee(Employee employee) {

    if (employee instanceof FullTimeEmployee) {
       FullTimeEmployee fullTimeEmployee = (FullTimeEmployee) employee;
       calcSalaray(fullTimeEmployee);


    } else if (employee instanceof PartTimeEmployee) {
        PartTimeEmployee partTimeEmployee = (PartTimeEmployee) employee;
        calcHourlywage(partTimeEmployee);
    }

}

1 个答案:

答案 0 :(得分:1)

以下是使用访客模式的简单示例。你的类是实体的事实是无关紧要的。重要的是基类具有固定的,众所周知的子类数。

让我们从抽象类开始:

public abstract class Employee {
    public abstract void accept(EmployeeVisitor visitor);
}

它包含一个以访问者为参数的accept()方法。每个子类都必须覆盖此方法。

现在有两个子类,每个子类都有一组不同的字段和方法:

public class FrenchEmployee extends Employee {

    private int eiffelTowerVisits;

    @Override
    public void accept(EmployeeVisitor visitor) {
        visitor.visit(this);
    }

    public int getEiffelTowerVisits() {
        return eiffelTowerVisits;
    }
}


public class EnglishEmployee extends Employee {

    private int towerBridgeVisits;

    @Override
    public void accept(EmployeeVisitor visitor) {
        visitor.visit(this);
    }

    public int getTowerBridgeVisits() {
        return towerBridgeVisits;
    }
}

这位访客是什么?它是一个为每个子类执行特定操作的接口:

public interface EmployeeVisitor {
    void visit(EnglishEmployee employee);
    void visit(FrenchEmployee employee);
}

以下是一个使用示例,与instanceof的使用情况相比:

public class EmployeeService {

    public void displayEmployeeWithUglyInstanceof(Employee employee) {
        if (employee instanceof EnglishEmployee) {
            EnglishEmployee english = (EnglishEmployee) employee;
            System.out.println("An English employee that visited the tower bridge " + english.getTowerBridgeVisits() + " times");
        }
        else if (employee instanceof FrenchEmployee) {
            FrenchEmployee french = (FrenchEmployee) employee;
            System.out.println("A French employee that visited the eiffel tower " + french.getEiffelTowerVisits() + " times");
        }
    }

    public void displayEmployeeWithVisitor(Employee employee) {
        EmployeeVisitor visitor = new EmployeeVisitor() {
            @Override
            public void visit(EnglishEmployee employee) {
                System.out.println("An English employee that visited the tower bridge " + employee.getTowerBridgeVisits() + " times");
            }

            @Override
            public void visit(FrenchEmployee employee) {
                System.out.println("A French employee that visited the eiffel tower " + employee.getEiffelTowerVisits() + " times");
            }
        };

        employee.accept(visitor);
    }
}

您可能会将其视为过度工程,但在Hibernate实体的情况下,它实际上非常有用,因为Hibernate使用动态代理来实现惰性关联。因此,员工很可能不是英国雇员,也不是法国雇员。在这种情况下,instanceof将在两种情况下都返回false,并且您的代码将不会执行任何操作。而对于访问者,代理人会将呼叫委托给它所包装的法国或英国员工,一切都会顺利进行。

另一个优点是,如果您添加了SpanishEmployee,您将立即看到必须修改的所有访客实施以处理西班牙员工。