【问题标题】:Spring-4 - Refactoring use of instanceof for calling appropriate methodSpring-4 - 重构使用 instanceof 来调用适当的方法
【发布时间】:2016-10-20 02:38:17
【问题描述】:

我有以下一组接口和类。 注意doSomething 方法。在调用对象的接口方法之前,它必须检查对象的实例。我想避免这种情况,因为它涉及在添加新车辆时更改此方法。在 Spring 中执行此操作的最佳方法是什么?

class SomeService {
  @Autowired
  VehicleRepairService<Car> carRepariService;

  @Autowired
  VehicleRepairService<Truck> truckRepairService;


  public void doSomething(String vehicleId) {
     Vehicle vehicle = getVehicle(vehicleId);
     if(vehicle instanceof Car) {
        carRepairService.repair(vehicle);
     } else {
        truckRepairService.repair(vehicle);
     }
  }
}

interface VehicleRepairService<T extends Vehicle> {
  void repair(T vehicle);
}

class CarRepairService implements VehicleRepairService<Car> {
    @Autowired
    SomeDependency some;

    void repair(Car vehicle) {
    .......
    }
}

class TruckRepairService implements VehicleRepairService<Car> {
  @Autowired
  DifferentDependency different;

   void repair(Truck vehicle) {
    .......
    }
}

【问题讨论】:

    标签: java spring-4


    【解决方案1】:

    因为没有一个答案有一个通用的解决方案。 Spring 允许注入一个类型的所有实现。下面的解决方案未经测试,我是在文本编辑器中编写的。可以通过使 VehicleRepairService 成为抽象类并使用例如 ResolvableType 检索此抽象类中的泛型类型来改进它。不再需要在每个实例中实现 getType 方法。

    class SomeService  {
    
        @Autowired
        private List<VehicleRepairService> vehicleRepairServices;
    
    
        public void doSomething(String vehicleId) {
            Vehicle vehicle = getVehicle(vehicleId);
            for(VehicleRepairService vehicleRepairService:vehicleRepairServices){
                if(vehicle.getClass().equals(vehicleRepairService.getType())){
                    vehicleRepairService.repair(vehicle);
                }
            }
        }
    
        public Vehicle getVehicle(String id){
            return new Truck();
        }
    }
    
    interface VehicleRepairService<T extends Vehicle> {
        void repair(T vehicle);
    
        Class<T> getType();
    }
    
    class CarRepairService implements VehicleRepairService<Car> {
    
        public void repair(Car vehicle) {
        }
    
        @Override
        public Class<Car> getType() {
            return Car.class;
        }
    }
    
    class TruckRepairService implements VehicleRepairService<Truck> {
    
        public void repair(Truck vehicle) {
        }
    
        @Override
        public Class<Truck> getType() {
            return Truck.class;
        }
    }
    

    【讨论】:

    • 如果与ResolvableType 结合使用,看起来是最接近理想的解决方案。我也没有看到任何其他更好的解决方案/方法。这确实有助于维护开闭原则。
    • 理论上它是完全通用的,您可以创建一个充当调度程序的实现,因此您只在一个类中拥有此列表内容
    • 在我看来它不是通用的,它也没有保留开闭原则。因为您按确切类型将汽车绑定到服务,所以您正在比较类型。它只是隐藏了问题,并没有解决它。下一个程序员将​​需要解码你的想法,getType 是不必要的,它有什么用?这个方法需要公开吗?您是否打算在代码中创建更多比较类型的位置?如果绑定汽车到服务的政策发生变化怎么办?
    • 正如我在评论中所写,您可以创建一个包含 for 循环部分的 VehiceRepairService 实现,并且您只使用此类。由于继承,因此不需要公共方法。
    【解决方案2】:

    一般来说,如果你有instanceofswitchif .. else if ..s,你可以考虑使用Visitor pattern。对于您的代码,它的含义是这样的:

    interface Vehicle
    {
        public interface Visitor<T>
        {
            T visit(Car car);
            T visit(Truck truck);
        }
    
         <T> T accept(Visitor<T> visitor);
    }
    
    class Car implements Vehicle
    {
    
        @Override
        public <T> T accept(Visitor<T> visitor)
        {
            return visitor.visit(this);
        }    
    };
    
    class Truck implements Vehicle
    {
        @Override
        public <T> T accept(Visitor<T> visitor)
        {
            return visitor.visit(this);
        }
    };
    

    然后,您可以在需要区分特定实例的地方创建一个新的访问者,可以是内联的,也可以作为单独的类:

    Vehicle.Visitor<Void> repairVisitor = new Vehicle.Visitor<Void>()
    {
    
        @Override
        public Void visit(Car car)
        {
            carRepairService.repair(car);
            return null;
        }
    
        @Override
        public Void visit(Truck truck)
        {
            truckRepairService.repair(truck);
            return null;
        }
    };
    vehicle.accept(repairVisitor);
    

    请注意,我将访问者设为通用。然后你也可以让访客返回一些东西。

    【讨论】:

    • 如果我添加一个新的车辆,那么我将不得不修改访问者界面。那不是我要找的。我要遵循开闭原则。
    • 是的,你是对的,如果不同车辆的数量经常变化,这并不理想。另一方面,您必须手动查找每个出现的if ..instanceof.. else..,而这里的代码在您扩展访问者之前不会编译。另一种方法是重组代码以将 repairService 作为每辆车的依赖项。
    • Vehicle 是一个实体,而不是一个服务。所以在vehicle注入repairService并不理想
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多