Это хорошая практика, особенно если разные классы имеют политики с одинаковыми именами, и вы не хотите путать их. Если вы не беспокоитесь об этом, то иногда просто не так просто вывести их из класса. Впрочем, это довольно часто встречается в качестве языка Java.
Обычно вы видите только базовый внутренний класс, если он абстрактный. Вы абсолютно не должны иметь различных конструкторов для Car
, основанных на них в качестве аргументов. Вы не разделяете свои проблемы и не делаете политику заменяемой .
class Base {
public:
Base(SomeAbstractPolicy *policy);
struct SomeAbstractPolicy {
virtual ~SomeAbstractPolicy() {}
virtual void stuff() = 0;
};
};
Иногда ленивцы будут жаловаться на инверсию управления такими конструкциями. Размещение конкретных политик в одном заголовке или в качестве статических помощников в классе может быть разумным компромиссом.
class Base {
public:
Base(SomeAbstractPolicy *policy);
struct SomeAbstractPolicy {
virtual ~SomeAbstractPolicy() {}
virtual void stuff() = 0;
};
static SomeAbstractPolicy *CreateAwesomeConcretePolicy();
static SomeAbstractPolicy *CreateSweetConcretePolicy();
};
Вы могли бы пойти дальше и использовать именованный конструктор.
class Base {
public:
Base CreateAwesomeBase();
Base CreateSweetBase();
private:
struct SomeAbstractPolicy {
virtual ~SomeAbstractPolicy() {}
virtual void stuff() = 0;
};
Base(SomeAbstractPolicy *policy);
SomeAbstractPolicy *policy;
};
Модульное тестирование - это намного сложнее, хотя оно того стоит.
Если у вас не может быть одного конструктора, основанного на вашей абстрактной политике, тогда абстракция принадлежит Car, а не этой политике. Обычно это более простое решение, когда вы делаете такие изменения. Запах кода для этого заключается в том, что вы видите, что методы со всем телом - это ветвь типа.