У меня есть два связанных интерфейса, но я не уверен, как распределить некоторые обязанности (методы).
Допустим, один интерфейс - Truck, а другой - ParkingLot.
Могут быть разные реализации Truck, такие как DumpTruck, BoxTruck, FireTruck ..., и разные реализации ParkingLot, такие как 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 или в интерфейсе Грузовика.
С одной стороны, я считаю, что эти методы должны быть в интерфейсе ParkingLot, поэтому клиенту нужно только получить доступ к классам TruckParkingLot y, чтобы получить всю необходимую ему информацию и управлять ею.Кроме того, с помощью отражателя вы можете легко управлять любым экземпляром класса (включая частный), не зная, сколько переменных экземпляра или какие переменные экземпляра имеет данный объект.
С другой стороны, поместив эти два метода вЗатем через интерфейс ParkingLot этот интерфейс управляет данными, которые не встроены в TruckParkingLot, но взяты из переменных экземпляра данного Truck, нарушая принципы проектирования, основанные на ответственности (экземпляры частного класса должны обрабатываться только в пределах класса, к которому они относятся.принадлежат).Кроме того, если обновление и печать идут в интерфейс ParkingLot, то интерфейс Truck становится пустым интерфейсом (для Truck больше нет методов).
С другой стороны, если я реализую эти два метода в Truckинтерфейс, то я буду дублировать код для каждой реализации этого интерфейса, так как способ обновления или печати переменных экземпляра BoxTruck и DumpTruck практически одинаков, если это делается с помощью геттеров и сеттеров (и полностью такой же, если онсделано с отражением)
Другое возможное решение - создать абстрактный класс для Truck и реализовать методы обновления и печати, а остальные грузовики просто наследуют этот класс.(Должен ли я все еще создавать интерфейс для этого абстрактного класса?).
В итоге, я имел в виду эти параметры, когда впервые писал этот пост:
A) Интерфейс ParkingLot со всемиметоды;Интерфейс Truck без методов (пустой).
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 с его методами, Интерфейс TruckLot с методами обновления и печати.
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)
Но на самом деле я ни в чем не уверен.
Заранее спасибо.