在相关接口之间分配责任

时间:2018-06-08 22:58:53

标签: java class methods reflection interface

我有两个相关的接口,但我不确定如何分配一些职责(方法)。

让我们说一个界面是卡车,另一个是ParkingLot。

可以有不同的Truck实现,例如DumpTruck,BoxTruck,FireTruck ......,以及TruckLark的不同实现,如TruckParkingLot,CarParkingLot,MotorcycleParkingLot ......

我有一个程序基本上是TruckParkingLot,它包含以下内容:

 private Map<String, Truck> trucks = new ConcurentHashMap();

 public void registerTruck(String plate, Truck truck) {
      // Code to put a new Truck in the ParkingLot
 }

 public void removeTruck(String plate) {
      // Code to remove a Truck from the ParkingLot
 }

 public Truck getTruckByPlate(String plate) {
      // Code to get Truck with key (plate) from the Map trucks
  }

然后是Truck接口,它有几个实现。每个实现都与其他实现不同,因为它们具有不同的实例变量。

我还想实现另外两种方法:更新和打印。前者更新所选卡车的实例变量;后者打印所选卡车的实例变量。

我怀疑的是,这些方法应该在ParkingLot界面还是在Truck界面中。

一方面,我觉得这些方法应该在ParkingLot界面中,因此客户只需要访问TruckParkingLot y类来获取它想要的所有信息并进行管理。此外,通过反射,您可以轻松管理类的任何实例(包括私有),而无需知道给定对象有多少实例变量或哪些实例变量。

另一方面,通过将这两种方法放在ParkingLot界面中,该界面然后管理不是内置在TruckParkingLot中的数据,而是来自给定Truck的实例变量,违反了责任驱动的设计原则(私有类实例只应在它们所属的类中处理)。此外,如果更新和打印转到ParkingLot界面,那么Truck接口将成为一个空接口(没有更多卡车方法)。

第三方面,如果我在Truck接口中实现这两个方法,那么我将为此接口的每个实现复制代码,因为更新或打印BoxTruck和DumpTruck的实例变量的方式几乎是如果使用getter和setter完成相同(如果用反射完成则完全相同)

另一种可能的解决方案是为Truck创建一个抽象类并实现更新和打印方法,其余的卡车只是继承了这个类。 (我是否仍然必须为这个抽象类创建一个接口?)。

总之,我在写这篇文章时已经考虑过这些选项:

A)所有方法的ParkingLot接口;卡车界面没有方法(空)。

 interface ParkingLot {
     public void registerVehicle(String plate, Vehicle vehicle);
     public void removeVehicle(String plate);
     public Vehicle getVehicleByPlate(String plate);
     public void updateVehicle(Vehicle vehicle);
     public void printVehicleData(Vehicle vehicle);
 }

 public class TruckParkingLot implements ParkingLot {
     private Map<String, Truck> trucks = new ConcurentHashMap();

     public void registerVehicle(String plate, Vehicle truck) {
         // Code to put a new Truck in the ParkingLot
     }

     public void removeVehicle(String plate) {
          // Code to remove a Truck from the ParkingLot
     }

     public Truck getVehicleByPlate(String plate) {
         // Code to get Truck with key (plate) from the Map trucks
     }

     public Truck updateVehicle(Vehicle truck) {
         // Code to update the inst vars of a Truck using reflection
     }

     public Truck printVehicleData(Vehicle truck) {
         // Code to print the inst vars of a Truck using reflection
     }
 }

 interface Truck extends Vehicle {
     // Nothing here
 }

 public class DumpTruck implements Truck {
     // Private instance variables
     // Constructor
     // Setters and getters
 }

 public class BoxTruck implements Truck {
     // Other private instance variables
     // Another constructor
     // Setters and getters
 }

B)ParkingLot界面及其方法,卡车界面,更新和打印方法。

 interface ParkingLot {
     public void registerVehicle(String plate, Vehicle vehicle);
     public void removeVehicle(String plate);
     public Vehicle getVehicleByPlate(String plate);
 }

 public class TruckParkingLot implements ParkingLot {
     private Map<String, Truck> trucks = new ConcurentHashMap();

     public void registerVehicle(String plate, Vehicle truck) {
         // Code to put a new Truck in the ParkingLot
     }

     public void removeVehicle(String plate) {
          // Code to remove a Truck from the ParkingLot
     }

     public Truck getVehicleByPlate(String plate) {
         // Code to get Truck with key (plate) from the Map trucks
     }
 }

 interface Truck extends Vehicle {
     public void updateVehicle(Vehicle vehicle);
     public void printVehicleData(Vehicle vehicle); 
     // Both methods should actually be inherited from Vehicle
     // interface, but this doesn't affect the point here.
     // Technically the Truck methods would still be empty.
 }

 public class DumpTruck implements Truck {
      // Private instance variables
      // Constructor
      // Setters and getters

      public Truck updateVehicle(Vehicle truck) {
          // Code to update the inst var using setters and getters
      }

     public Truck printVehicleData(Vehicle truck) {
         // Code to print the inst var using setters and getters
     }
 }

 public class BoxTruck implements Truck {
     // Other private instance variables
     // Another constructor
     // Setters and getters

     public Truck updateVehicle(Vehicle truck) {
         // Code to update the inst vars using setters and getters
     }

     public Truck printVehicleData(Vehicle truck) {
         // Code to print the inst vars using setters and getters
     }
 }

C)ParkingLot接口与它的方法,卡车抽象类。

interface ParkingLot {
     public void registerVehicle(String plate, Vehicle vehicle);
     public void removeVehicle(String plate);
     public Vehicle getVehicleByPlate(String plate);
 }

 public class TruckParkingLot implements ParkingLot {
     private Map<String, Truck> trucks = new ConcurentHashMap();

     public void registerVehicle(String plate, Vehicle truck) {
         // Code to put a new Truck in the ParkingLot
     }

     public void removeVehicle(String plate) {
          // Code to remove a Truck from the ParkingLot
     }

     public Truck getVehicleByPlate(String plate) {
         // Code to get Truck with key (plate) from the Map trucks
     }
 }

 public abstract class Truck implements Vehicle {
     // private common instance variables to all trucks
     // Constructor with all common instance variables
     // Setters and getters

     public Truck updateVehicle(Vehicle truck) {
         // Code to update the inst vars using setters and getters
     }

     public Truck printVehicleData(Vehicle truck) {
         // Code to print the inst vars using setters and getters
     }
 }

 public class DumpTruck implements Truck {
     // Private unique instance variables to DumpTruck
     // Inherit constructor from superclass
     // + initialize unique instance variables for this subclass
     // Setters and getters for the unique inst vars of this subclass

     @override
     public Truck updateVehicle(Vehicle truck) {
         // inherit code from superclass 
        // + update the unique instance variables of this subclass
     }

     @override
     public Truck printVehicleData(Vehicle truck) {
         // inherit code from superclass
         // + print the unique instance variables of this subclass
     }
 }

 public class BoxTruck implements Truck {
     // Private unique instance variables to DumpTruck
     // Inherit constructor from superclass
     // + initialize unique instance variables for this subclass
     // Setters and getters for the unique inst vars of this subclass

     @override
     public Truck updateVehicle(Vehicle truck) {
         // inherit code from superclass
         // + update the unique instance variables of this subclass
     }

     @override
     public Truck printVehicleData(Vehicle truck) {
         // inherit code from superclass
         // + print the unique instance variables of this subclass
     }
 }

就个人而言,我更喜欢在ParkingLot界面中使用所有方法并使用反射(选项A),将Truck接口留空;或使用Truck的抽象类(选项C)

但是,实际上,我不确定任何事情。

提前致谢。

1 个答案:

答案 0 :(得分:1)

我相信真正的OOP设计要求类型能够非常模仿它们所代表的真实世界对象。我假设当调用update()时,您打算从数据存储中检索某些值,然后依次更新实例变量。如果这是正确的,它会使你的对象变得可变,这可能是糟糕的设计。

我看待它的方式,卡车从车库出来,进入现实世界的车库,这也是你的对象结构应该做的事情。你可以更新&#34;卡车通过卡车进入车库界面。并且为了使卡车不可变,该方法然后传回新卡车的实例。例如:

interface Garage {
        Truck service(final Truck truck);
}

服务方法是您的&#34;更新&#34;方法也更接近地模仿现实世界领域。就印刷而言,我建议完全是另一个类,这个类的构造函数会因各种类型的卡车而过载,所以你可以分开处理它们。

interface TruckPrinter {
        void print();
}
class BasicTruckPrinter implements TruckPrinter {
        private String output;
        BasicTruckPrinter(final DumpTruck truck) { /* convert truck to output */ }
        BasicTruckPrinter(final FireTruck truck) { ... }
        BasicTruckPrinter(final BoxTruck truck) { ... }

        void print() {
              System.out.println(output);
        }
}       

希望这会有所帮助......