analizer 05.10.2011 20:15 mcabber

пстач, вот тоже интересная задачка: есть два ортогональных интерфейса-стратегии. хочется создать объект, который оба их будет реализовывать, но, при этом, реализацию для каждого из них, будет получать в момент конструирования. вопрос, как реализации задавать и как этот объект конструировать? использовать PImplинг не интересно. Шаблон и наследоваться от параметров — тоже, ибо на две стратегии четыре ветки кода, а на три — уже девять.

Recommended by: @magog
1. DZhon 06.10.2011 04:18

Забабахать паттерн Builder, чтобы потом сделать нечто вроде:
Builder b;
b.addIface1Impl1().addIface2Impl2();
либо
b.addIface1(new Impl1()).addIface2(new Impl2());

Скажем, если сделать просто b.addIface2Impl2();, то первый будет по-умолчанию. Методы add_ из Builder каждый раз возвращают ссылку на него (для связывания вызовов в цепочку).

Для непосредственного создания вызывать b.create(), который вернет уже готовый продукт.

2. kbDZhon /1 06.10.2011 08:37

ну, то есть, по сути — глупость изначального вопроса в том, что объект будет реализовывать две стратегии, при этом получая конкретную из них (до конца жизни) в момент конструирования. тогда нафига ему вторая стратегия? при builder таки получит одну-единственную.

p.s.: это я так, убедиться, что всё правильно понял. или не?

3. analizerkb /2 06.10.2011 08:41 mcabber

он получает две ортогональные стратегии. сделано для того, чтобы иметь единую точку входа для нескольких стратегий переданных в функцию, а не тащить стопицот разных указателей

4. analizerDZhon /1 06.10.2011 08:43 mcabber

несколько не то, но идея хорошая. можно генерить типы на лету используя подобные цепочки вызовов

5. DZhonkb /2 06.10.2011 08:43

Две стратегии ему, потому что они ортогональны, как я понел. Цепочка вызовов builder будет добавлять их обе, не понял фразу:
>при builder таки получит одну-единственную.

6. kbanalizer /3 06.10.2011 08:43 c8541125

подожди. что значит ортогональные? интерфейс взаимодействия с ними, что ли, разный будет? или какая вообще разница?

7. DZhonanalizer /4 06.10.2011 08:43

Да, именно в этом соль.

8. analizerkb /6 06.10.2011 08:47 mcabber

две стратегии реализуют два интерфейса

9. analizeranalizer /8 06.10.2011 08:47 mcabber

при этом, доступ к методам осуществляется через один указатель

11. kbanalizer /8 06.10.2011 08:48 c8541125

а нужная потом выбирается в рантайме, что ли? что ж это за стратегии тогда такие? (или это не те стратегии, которые паттерн?)

12. DZhonkb /11 06.10.2011 08:52

У тебя П(аттерн)ГМ штоле ? :)

Iface1 {
f();
}

Iface2 {
g();
}

Impl {
Iface1 * subImpl1;
Iface2 * subImpl2;

f() {
subImpl1→f();
}
g() {
subImpl2→g();
}
}

-- я так понял мысль афтара (на псевдокоде).

13. analizerkb /11 06.10.2011 08:54 mcabber

да не выбирается ничего. просто в функции может быть нужно std::vector<char> IDataStorage::GetData(const char* key); и void ILogger::Log(const char* str); а также over 9000 других интерфейсов. и мне хочется все эти интерфейсы передать как указатель на IWorkingEnvironment, чтобы через него всё делать

14. kbanalizer /13 06.10.2011 08:57 c8541125

и потом делать work_env→logger→log() и work_env→data_storage→get_data() и т.п.? (уж прости, мне реально интересно)

15. analizerkb /14 06.10.2011 09:00 mcabber

work_env→log() & work_env→get_data(). пример я выбрал неудачный, но на практике две вызываемые функции вполне уместны в рамках одного интерфейса

16. kbDZhon /12 06.10.2011 09:01

блеать. короче:
- "два ортогональных интерфейса-стратегии" означает, что они никак друг с другом не связаны, так? (логгер и получатель данных, как в примере выше)
- выбор каждого из них (привязка) происходит при конструировании

в этом задача? :-)

17. analizerkb /16 06.10.2011 09:03 mcabber

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

18. analizeranalizer /17 06.10.2011 09:04 mcabber

при этом, просто унаследоваться от обоих и сделать реализацию нельзя — ибо поинтер на реализацию придёт снаружи

19. DZhonDZhon /12 06.10.2011 09:05

Можно сделать здесь Impl наследником от обоих интерфейсов, тогда он вполне сможет везде за них сойти. Декоратор это называется, насколько я помню.

20. analizerDZhon /19 06.10.2011 09:05 mcabber

надо подумать

21. kbanalizer /18 06.10.2011 09:06 c8541125

аа, понял. вопрос, как реализовать этот work_env. так? а чем не подойдёт /12? или описывать каждый метод руками в Impl не кошерно?

22. analizerkb /21 06.10.2011 09:08 mcabber

не кошерно

23. DZhonanalizer /22 06.10.2011 09:10

Зделой оператор приведения типа к интерфейсу, это же плюсы!
operator Iface1 () {
return subImpl1;
}

24. kbanalizer /22 06.10.2011 09:11 c8541125

ладно. как по мне — кошерно, потому что читать код понятнее (пошел в Impl, увидел функции, увидел куда ведут :-) типа как app→log() делает this→logger→log() — очень понятно всё.

25. DZhonDZhon /23 06.10.2011 09:11

Мля, местами переставил в сигнатуре сущности.

26. analizeranalizer /22 06.10.2011 09:12 mcabber

очень уж меня будет напрягать дублирование имён типов в:
class IWorkingEnvironment: public IDataStorage, public ILogger {
std::unique_ptr<IDataStorage> DataStorage;
std::unique_ptr<ILogger> Logger;

public:
...
std::vector<char> GetData(const char* key) {
Data→GetData(key);
}
void Log(const char* str) {
Logger→Log(str);
}
};

27. analizerDZhon /23 06.10.2011 09:12 mcabber

а взлетит?

28. analizeranalizer /27 06.10.2011 09:14 mcabber

ща попробую

29. DZhonanalizer /27 06.10.2011 09:17

Не взлетит, если наследоваться от этих же интерфейсов.
Ну и нельзя будет вызвать как:
Impl x;
x→f();

Зато можно будет передать туда, где ждут iface1, ну и зделоть
Iface xif = x;
xif→f();

30. DZhonDZhon /29 06.10.2011 09:19

В общем, я бы не ебал моцк и делал:
x→getIface1()→f();

Так хоть семантически понятно, что ты и от кого хочешь.

31. DZhonDZhon /30 06.10.2011 09:19

Возвращать, конечно же, shared_ptr через getIface1() ;)

32. analizerDZhon /29 06.10.2011 09:21 mcabber

совсем не взлетит. ибо класс должен наследоваться от IWorkingEnvironment, в котором чисто виртуальные методы, которые таки придётся переопределить

33. DZhonanalizer /32 06.10.2011 09:22

Архитектуропроблемы, да.
Выбирай, в общем.

Do you really want to delete ?