今天我读了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);
}
}
答案 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,您将立即看到必须修改的所有访客实施以处理西班牙员工。