class System
{
public:
//...
private:
class Subsystem1;
Subsystem1* _s1; //ну или auto_ptr
}
Единственный на мой взгляд недостаток — все остальные private члены класса видны в Subsystem1, но с этим вполне можно жить. Bridge делать не захотел — овчинка не стоит выделки в моем случае.
Есть некая реализация штуковины System из предметной области. Она включает несколько подсистем:
//заголовок system.hclass Subsystem1;
class Subsystem2;
class Subsystem3;
class System
{
Subsystem1* _s1;
Subsystem2* _s1;
Subsystem2* _s2;
public:
System();
~System();
//интерфейс System void some_method();
//часть методов используется только subsystem1void used_only_by_subsystem1();
//часть методов используется только subsystem2void used_only_by_subsystem2();
};
//реализация методов system.cpp#include"system.h"#include"subsystem1.h"#include"subsystem2.h"//etc...
System::System()
{
//создаем подсистему
_s1 = new Subsystem1; //аналогично для Subsystem1, Subsystem2, ...
}
void System::some_method()
{
//используем ее
_s1->some_method();
}
System::~System()
{
//убираем за собойdelete _s1;
}
//заголовочный файл subsystem1.hclass System;
class Subsystem1
{
System* _owner;
public:
Subsystem1(System* o);
void some_method();
};
//реализация методов - файл subsystem1.cpp#include"subsystem1.h"#include"system.h"
Subsystem1::Subsystem1(System* o):_owner(o){}
void Subsystem1::some_method()
{
//...
//иногда приходится что-то делать с владельцем
_owner->used_only_by_subsystem1();
}
Получается, что:
1.заголовочные файлы, описывающие подсистемы не включаются в system.h (это хорошо, так как подсистемы — деталь реализации)
2. заголовочный файл системы не включается в заголовочный файл подсистемы (это тоже хорошо, так как интерфейс подсистемы не зависит от системы)
Хотелось бы, сохраняя свойства 1 и 2, как-то убрать методы used_by_subsyst из public секции описания класса System потому что они только замусоривают интерфейс системы,
а по факту используются только при ее реализации. Как этого добиться проще всего не теряя скорости выполнения?
Здравствуйте, andyp, Вы писали:
A>Здравствуйте,
A>Есть некая реализация штуковины System из предметной области. Она включает несколько подсистем:
A>Получается, что: A>1.заголовочные файлы, описывающие подсистемы не включаются в system.h (это хорошо, так как подсистемы — деталь реализации) A>2. заголовочный файл системы не включается в заголовочный файл подсистемы (это тоже хорошо, так как интерфейс подсистемы не зависит от системы)
A>Хотелось бы, сохраняя свойства 1 и 2, как-то убрать методы used_by_subsyst из public секции описания класса System потому что они только замусоривают интерфейс системы, A>а по факту используются только при ее реализации. Как этого добиться проще всего не теряя скорости выполнения?
pimpl не подойдет?
class System {
struct SystemImpl;
auto_ptr<SystemImpl> m_impl;
public:
System();
~System();
void some_method(); //интерфейс System
};
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, andyp, Вы писали:
A>>Здравствуйте,
A>>Есть некая реализация штуковины System из предметной области. Она включает несколько подсистем:
A>>Получается, что: A>>1.заголовочные файлы, описывающие подсистемы не включаются в system.h (это хорошо, так как подсистемы — деталь реализации) A>>2. заголовочный файл системы не включается в заголовочный файл подсистемы (это тоже хорошо, так как интерфейс подсистемы не зависит от системы)
A>>Хотелось бы, сохраняя свойства 1 и 2, как-то убрать методы used_by_subsyst из public секции описания класса System потому что они только замусоривают интерфейс системы, A>>а по факту используются только при ее реализации. Как этого добиться проще всего не теряя скорости выполнения?
NB>pimpl не подойдет? NB>
On 01/16/2012 05:30 PM, andyp wrote:
> Хотелось бы, сохраняя свойства 1 и 2, как-то убрать методы used_by_subsyst из > public секции описания класса System потому что они только замусоривают > интерфейс системы, > а по факту используются только при ее реализации. Как этого добиться проще всего > не теряя скорости выполнения?
Варианты
0) private, friend
1) выделить общение Sustem/Subsystem в систему встречнонаправленных интерфейсов
(Bridge), сами интерфейсы -- private, friend
Здравствуйте, MasterZiv, Вы писали:
MZ>Варианты MZ>0) private, friend
думал так. Грубоват контроль над доступностью методов получается.
MZ>1) выделить общение Sustem/Subsystem в систему встречнонаправленных интерфейсов MZ>(Bridge), сами интерфейсы -- private, friend
Вы имеете в виду паттерн Bridge? Написать абстрактные интерфейсы System->Subsystem и Subsystem->System, сделать конкретные реализации для System и Subsystem, в которых хранить указатели на соответствующие абстрактные классы?
Здравствуйте, andyp, Вы писали:
A>Хотелось бы, сохраняя свойства 1 и 2, как-то убрать методы used_by_subsyst из public секции описания класса System потому что они только замусоривают интерфейс системы, A>а по факту используются только при ее реализации. Как этого добиться проще всего не теряя скорости выполнения?
Ну казалось бы.
Есть интерфейс System — для всех.
Есть интерфейсы Subsystem1..3 — для System.
Есть интерфейсы Owner1..3 — для Subsystem1..3 соответственно.
Можно решить задачу даже без идиоматеских подходов, а чисто на ООП.
Класс SystemImpl реализует 4 интерфейса — System, Owner1..3.
Пользователи имеют дело с умным указателем на System.
Конструктор класса SystemImpl создаёт объекты SubsystemImpl1..3 с интерфейсами Subsystem1..3, отдавая им указатели на свои интерфейсы Owner1..3 соответственно.
Связку интерфейс-реализация (System-SystemImpl) можно делать силами языка, то есть на виртуальных функциях, а можно своими силами, то есть на идиоме pimpl.
Честно сказать, я не уверен, что pimpl даст реальный выигрыш в скорости (хотя, конечно, там на одну косвенность меньше, чем при вызове виртуальной функции). Надо профилировать.
Связки интерфейсов-реализаций остальных типов можно делать статическими.
Для SubsystemN-SubsystemImplN это тривиально (это один и тот же тип).
А для OwnerN-SubsystemImpl это или будет "всё для всех" (т.е. Subsystem1 будет видеть Owner2, потому что Owner1=Owner2=Owner3=SystemImpl), или придётся использовать идиому CRTP.
А можно и не нахлобучиваться, а сделать и это тоже на виртуальных функциях.
На всякий случай: как это делается на CRTP.
// owner1.hclass SystemImpl;
template<class Impl>
struct Owner1T
{
void foo() { static_cast<Impl*>(this)->foo_impl(); }
// без шаблона мы не смогли бы так легко выполнить статический downcast
};
typedef Owner1T<SystemImpl> Owner1; // внимание! шаблон параметризован недообъявленным типом!
// subsystem1.h#include"owner1.h"class Subsystem1
{
public:
Subsystem1(Owner1* owner) : owner_(owner) {}
private:
Owner1* owner_;
void call_foo(); // нам обязательно надо видеть объявление SystemImpl
};
// subsystem1.cpp#include"systemimpl.h"void Subsystem1::call_foo() { owner_->foo(); }
// systemimpl.h#include"owner1.h"#include"subsystem1.h"class SystemImpl : ....., private Owner1
{
....
void foo_impl(); // либо public, либо надо объявить friend Owner1
};
> MZ>Варианты > MZ>0) private, friend > > думал так. Грубоват контроль над доступностью методов получается.
Ну, в общем-то с точностью до конкретных методов, которым доверяют.
> > MZ>1) выделить общение Sustem/Subsystem в систему встречнонаправленных интерфейсов > MZ>(Bridge), сами интерфейсы -- private, friend > > Вы имеете в виду паттерн Bridge? Написать абстрактные интерфейсы > System->Subsystem и Subsystem->System, сделать конкретные реализации для System > и Subsystem, в которых хранить указатели на соответствующие абстрактные классы?
On 01/16/2012 06:56 PM, andyp wrote:
> решил остановиться на идиоме pimpl: > > class System > { > public: > //... > private: > class Subsystem1; > Subsystem1* _s1; //ну или auto_ptr > }
Здравствуйте, MasterZiv, Вы писали:
MZ>On 01/16/2012 06:56 PM, andyp wrote:
>> решил остановиться на идиоме pimpl: >> >> class System >> { >> public: >> //... >> private: >> class Subsystem1; >> Subsystem1* _s1; //ну или auto_ptr >> }
MZ>Это и есть Bridge.
Не совсем. Вроде бы у Bridge должна иметь место быть абстракция System и Subsystem1? (по крайней мере так в книжке у Гаммы написано)
Здравствуйте, andyp, Вы писали:
A>Спасибо за бридж на шаблонах. Буду разбираться.
Там от шаблонов только трюк, чтобы обойти приведение типа во время компиляции. Без шаблона компилятор бы выругался на недообъявленный тип.
А вообще, CRTP — это compile-time аналог виртуальных функций.
Но это не бридж!
Это простое наследование реализации от интерфейса.
Сравни
> MZ>Это и есть Bridge. > > Не совсем. Вроде бы у Bridge должна иметь место быть абстракция System и > Subsystem1? (по крайней мере так в книжке у Гаммы написано)