Распределить обязанности между соответствующими интерфейсами - PullRequest
0 голосов
/ 09 июня 2018

У меня есть два связанных интерфейса, но я не уверен, как распределить некоторые обязанности (методы).

Допустим, один интерфейс - 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)

Но на самом деле я ни в чем не уверен.

Заранее спасибо.

1 Ответ

0 голосов
/ 09 июня 2018

Я считаю, что истинный дизайн ООП требует, чтобы Типы близко имитировали объекты реального мира, которые они представляют.Я предполагаю, что когда вызывается update (), вы намереваетесь получить некоторые значения из хранилища данных, которое затем, в свою очередь, обновляет переменные экземпляра.Если это правильно, это делает ваши объекты изменчивыми, что может быть плохим дизайном.

С моей точки зрения, грузовики выходят из гаража и въезжают в гараж в реальном мире, и это то же самое должна делать структура вашего объекта.Вы можете «обновить» свой Грузовик, передав его в интерфейс Garage.И для того, чтобы Грузовик был неизменным, метод затем передает экземпляр нового Грузовика.Например:

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

Где сервисный метод является вашим методом «обновления», но также более точно имитирует область реального мира.Что касается печати, я бы предположил, что это был бы вообще другой класс, и конструктор этого класса был бы перегружен для различных типов грузовых автомобилей, так что вы можете обрабатывать их отдельно по-разному.

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);
        }
}       

Надеюсь, этопомогает ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...