Альтернатива дизайна? Состав и конструкция - PullRequest
1 голос
/ 05 января 2010

Итак, я использую композицию, чтобы собрать коллекцию объектов, каждый из которых является производным от базового класса, скажем, Component. Например:

class Component {
public:
  Component();
  ...
private:
  int m_address;
  ...
};

class SpecializedComponent: public Component {
public:
  SpecializedComponent()
  ... //and so on
};

class SpecializedComponent2: public Component {
public:
  SpecialIzedComponent2()
  ... //and so on
};

class ComponentHolder{
  SpecializedComponent* m_descriptiveName;
  SpecializedComponent2* m_descriptiveName2;
  // and so on... many different types of components
}

Таким образом, каждый SpecializedComponentX будет связываться по сети с отдельным источником данных, каждый со своим уникальным адресом. Эти адреса указаны в файле параметров. В данный момент я анализирую файл параметров, и m_address инициализируется в конструкторе производного класса - это потому, что каждый m_address определяется типом объекта, который мы инициализируем.

Каждый SpecializedComponentX имеет некоторые общие функции, которые я хочу выполнить в компоненте базового класса. Итак, я раскручиваю поток, связанный с компонентом базового класса, верно? Конечно - имеет смысл. Пока я не пойму, что у меня еще нет адреса назначения для этого компонента - потому что объект не был полностью построен. Я хочу раскрутить поток базового класса в ctor, но я пока не знаю m_address.

Единственный способ обойти это - предоставить (простую) виртуальную функцию void start(), которую производный класс может вызывать для ускорения потока после того, как объект полностью построен. Это допустимый и соответствующий выбор дизайна или есть шаблон, который я мог бы пропустить? Благодарю.

Ответы [ 3 ]

0 голосов
/ 05 января 2010

Если эта общая функциональность каким-либо образом зависит от состояния SpecializedComponent, SpecializedComponent2 или того факта, что это SpecializedComponent или SpecializedComponent2, вы не сможете сделать это в конструкторе Component, если только вы не передадите параметры Это. Иногда необходимо передать идентификатор типа конструктору Component, чтобы выполнить такую ​​инициализацию.

В этом случае, однако, вы можете создать виртуальную функцию, которую может вызывать производный класс. Однако предположим, что вы помещаете этот вызов виртуальной функции в конструктор SpecializedComponent. Если позднее вы создадите еще один класс из этого (SuperSpecializedComponent) и перезапустите эту виртуальную функцию, то вызов, который вы сделаете из конструктора SpecialzedComponent, даже не попадет в него. Мораль: не вызывайте виртуальные функции из конструктора.

Я думаю, что самым чистым способом было бы иметь двухфазную конструкцию. Конструктор, который выполняет базовое подключение объекта и метод Init (), который должен быть вызван перед использованием. Код клиента (ComponentHolder?) Может вызывать этот Init после того, как все объекты полностью построены.

0 голосов
/ 05 января 2010

Почему метод start () должен быть виртуальным?

Вы можете сделать его не виртуальным и реализовать ваши производные конструкторы как это:

SpecializedComponent::SpecializedComponent() {
    m_address = getAddressFromParameterFile("SpecializedComponent");
    start();
}

Это предпочтительнее вызова start () после того, как объект полностью построено, так как двухступенчатая конструкция подвержена ошибкам. (Если вы делаете необходимо двухэтапное строительство, рассмотрим фабрику (или фабричный метод), чтобы убедитесь, что существуют только полностью построенные объекты. Сделать конструктор рядовой и заводской (метод) друг.)

Другим способом было бы перенести расчет адреса из строительство объекта. Это приведет к следующему коду:

SpecializedComponent::SpecializedComponent(const std::string& address)
 : Component(address)
{}

Component::Component(const std::string& address)
 : m_address(address)
{
    start();
}

Такой подход повышает тестируемость производных SpecializedComponents, потому что он удаляет зависимость от файл параметров.

Для удобства вы можете предоставить статический метод фабрики для экземпляра Ваши Специализированные Компоненты:

SpecializedComponent* SpecializedComponent::create() {
    std::string address = getAddressFromParameterFile("SpecializedComponent");
    return new SpecializedComponent(address);
}

Кстати: рассмотрите возможность хранения shared_ptr в ComponentHolder вместо необработанных указателей.

0 голосов
/ 05 января 2010

Компонент может иметь конструктор с одним аргументом, который инициализирует m_address.

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