我有两个相关的接口,但我不确定如何分配一些职责(方法)。
让我们说一个界面是卡车,另一个是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)
但是,实际上,我不确定任何事情。
提前致谢。
答案 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);
}
}
希望这会有所帮助......