Взаимодействующие классы - организационный код - PullRequest
2 голосов
/ 22 июля 2010

У меня проблемы с организацией классов.

Предположим, у меня есть класс ABase.Когда я хочу создать какую-то другую (более конкретную) абстракцию этого класса (обозначим это AParticular), я могу использовать наследование или просто композицию.Тогда к AParticular легко относиться как к ABase: в случае наследования это делается автоматически, в случае композиции я могу создать какой-то const ABase& AParticular::GetABasePart() метод.Благодаря этому я избегаю дублирования кода и получаю полиморфные функции.

Но когда у меня есть два или более классов, которые взаимодействуют друг с другом, у меня возникают некоторые проблемы с созданием аналогов этих классов в более конкретной абстракции.Например, предположим, у меня есть два класса Car и Station.В Station есть несколько общедоступных методов обслуживания автомобилей:

class Car {
  ...
}

class Station {
  ...
  void AddCarToPlaceNumberN(const Car& car, int place_number) {
    // adds car to some_container<Car>.
  }
  Car* GetMutableCarPointer(int place_number) {
    // gets mutable pointer from some_container<Car>.
  }
  ...
  some_container<Car> cars;
}

Теперь я хочу создать классы Truck и TruckStation: они очень похожи на классы Car и Station и имеют небольшие изменения.Чтобы понять проблему, достаточно подумать, поскольку они делают абсолютно то же самое, что и классы Car и Station, но их методы имеют немного другое имя (например, TruckStation :: AddTruckToPlaceNumberN вместо Station :: AddCarToPlaceNumberN)

Как организоватькод новых классов, обеспечивающих эти функции?

  1. Нет дублирования кода, я хочу использовать уже созданные методы класса Car и Station.
  2. Быстрое преобразование Truck & -> Car &, TruckStation &-> Station & (Необязательное наследование, состав также подходит), поскольку иногда я хочу трактовать Truck как Car, а TruckStation как Station.
  3. Все методы взаимодействия на уровне Car-Station должны быть реализованы на новом уровне Truck.-TruckStation.

Основная проблема - это 3-й предмет.Давайте рассмотрим два метода взаимодействия:

1) С этим методом все в порядке:

// If we use inheritance in creating Truck and TruckStation, then we just run
void TruckStation::AddTruckToPlaceNumberN(const Truck& car, int place_number) {
   AddCarToPlaceNumberN(car, place_number)
}
// If we use composition, then it is appropriate to run sth like that:
void TruckStation::AddTruckToPlaceNumberN(const Truck& car, int place_number) {
   station_.AddCarToPlaceNumberN(car.GetCarPart(), place_number);
}

2) Но я не знаю, как реализовать аналог Station :: GetMutableCarPointer ():

// For example, if TruckStation was inherited from Station, then suppose:
Truck* TruckStation::GetMutableTruckPointer() {
   Car* car = GetMutableCarPointer();
   // Ups! I need to return Truck*, not Car*.
}

Повторите вопрос: как я могу реализовать эти классы, чтобы обеспечить:

  1. без дублирования кода.
  2. Возможность рассматривать новые классы как их высшиеабстракции уровней.
  3. Методы реализации, такие как TruckStation :: GetMutableTruckPointer (), которые соответствуют Station :: GetMutableCarPointer ().

Tnx!

Ответы [ 2 ]

1 голос
/ 22 июля 2010

Ленивый способ - заставить станцию ​​использовать универсальный тип T так, чтобы;(Имейте в виду, мне не совсем понятен синтаксис наследования C ++, но принцип применим)

template<typename T>
class Station<T>:CarStation
{
    void Station<T>::StatAddCarToPlaceNumberN(const T& car, int place_number)
    {
    // adds car to some_container<T>.
    }

    T * Station<T>::GetMutableCarPointer(int place_number) 
    {
        // gets mutable pointer from some_container<Car>.
        return dynamic_cast<T>(car);
    }
}

И есть абстрактная станция суперкласса, которая реализует функцию для возврата базового указателя, скажем

class CarStation
{
    //...
    some_container<Car> cars;
    virtual Car * CarStation::GetMutableCarBasePointer(int place_number) = 0;

}

Car * CarStation::GetMutableCarBasePointer(int place_number)
{
       //gets mutable pointer to base class from some_container<T>
}

Теперь, если вы хотите, вы можете создать новый класс TruckStation (в этом я не уверен в C ++, я опять называю принцип)

class TruckStation : Station<Truck>
{
   //...
}

или просто перейти с Station<Truck>

1 голос
/ 22 июля 2010

Получение конкретного кода.Я бы сделал это следующим образом.

  1. Базовый класс Транспортное средство, расширенное специальными классами для легковых и грузовых автомобилей.
  2. Класс Станция с методами
    • void Station::AddVehicleToPlaceNumberN(const Vehicle& vehicle, int placeNumber)
    • Vehicle* Station::GetMutableVehiclePointer()

Причины, по которым проектирование / организация класса.1. Используйте наследование только тогда, когда есть необходимость в разных реализациях.Если разные реализации унаследованного метода делают одно и то же (как в случае AddVehicleToPlaceNumberN), то нет необходимости разделять реализации.2. Использование общего имени метода всегда помогает упростить код.Методы могут быть перегружены (переданы с другим числом и типом параметров), чтобы выполнить конкретную задачу.

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