Имеется абстрактный класс Document, его необходимо отобразить в виде некой абстрактной формы, скажем, DocumentForm. Document имеет два конкретных воплощения — входящий документ (InDocument) и исходящий документ (OutDocument). Отображаться необходимо на InDocumentForm и OutDocumentForm, соответственно.
Насколько я понял, идея отрыва абстракции от реализации заключается в том числе и в том, что про связь между ними знает только абстракция (причем "абстрактная" абстракция, т.е. базовый класс). Потомки же используют декларированные методы в базовом классе для доступа к фактической реализации (т.е. сами они про реализацию не в курсе).
Если предыдущий абзац не заблуждение, возникает следующий вопрос.
Допустим, я трактую как абстракцию — DocumentForm, а в качестве "утонченной" абстракции — InDocumentForm, реализация — Document, конкретная реализация — InDocument.
Как мне быть с тем, что InDocument имеет дополнительные поля, соответственно методы для доступа к ним, которых нет в Document? (Либо DocumentForm, либо InDocumentForm должен знать про InDocument)
Помогите разобраться, целесообразно ли использовать в данном случае шаблон мост? И как следует поступать если наследники не только конкретизируют базовый класс но и расширяют его функциональность (дело попахивает dynamic_cast<>)
Прикинул я тут, схемку UML наваял и вот что получил: у тебя там два моста будет.
// это код на С# class Document{}
class InDocumnet : Document{}
class OutDocumnet : Document{}
class InDocumnetBridge
{
private InDocumnet realDocument;
}
class OutDocumnetBridge
{
private OutDocumnet realDocument;
}
class InDocumnetForm : InDocumnetBridge{}
class OutDocumnetForm : OutDocumnetBridge{}
Здравствуйте, sapunidze, Вы писали:
S>Имеется абстрактный класс Document, его необходимо отобразить в виде некой абстрактной формы, скажем, DocumentForm. Document имеет два конкретных воплощения — входящий документ (InDocument) и исходящий документ (OutDocument). Отображаться необходимо на InDocumentForm и OutDocumentForm, соответственно. S>Насколько я понял, идея отрыва абстракции от реализации заключается в том числе и в том, что про связь между ними знает только абстракция (причем "абстрактная" абстракция, т.е. базовый класс). Потомки же используют декларированные методы в базовом классе для доступа к фактической реализации (т.е. сами они про реализацию не в курсе). S>Если предыдущий абзац не заблуждение, возникает следующий вопрос. S>Допустим, я трактую как абстракцию — DocumentForm, а в качестве "утонченной" абстракции — InDocumentForm, реализация — Document, конкретная реализация — InDocument. S>Как мне быть с тем, что InDocument имеет дополнительные поля, соответственно методы для доступа к ним, которых нет в Document? (Либо DocumentForm, либо InDocumentForm должен знать про InDocument) S>Помогите разобраться, целесообразно ли использовать в данном случае шаблон мост? И как следует поступать если наследники не только конкретизируют базовый класс но и расширяют его функциональность (дело попахивает dynamic_cast<>)
S>з.ы. S>class Document{ S>... S> Load() { LoadFromDB() } S> Save() { SaveToDB() } S>... S>}
S>class DocumentForm{ S>... S> DocumentForm(int id) { document = new Document(id) } S> OnShow() { document->Load() ... } S> OnButtonSaveClick { document->Save() } S>... S>}
Мне тут не очень понятен один аспект.
Если у тебя OutDocument отображается в OutDocumentForm, а InDocument в InDocumentForm, то есть ли смысл засовывать в каждую из форм Document. Пусть каждая из них работает со своим подклассом Document. И никакого динамиккаста не будет.
Или в этом есть какой — то потаенный смысл?
Здравствуйте, sapunidze, Вы писали:
S>честно говоря не очень понимаю что дает введение данных классов...
Что ты хотел
Например, у тебя есть документ "счёт-фактура" и ты хочешь отобразить его как входящий документ, тогда тебе надо сделать следующее:
class Invoice : InDocumentBridge
{
OnShow(){this.realDocument.Load();...}
OnButtonSaveClick{this.realDocument.Save();...}
}
Тут такая мысль проскочила, что ты возможно хочешь разделить документ и его представление. В этом случае не связывайся с мостом, он сюда немного не вписывается.
class Document{}
class InDocumnet : Document{}
class Invoice : InDocumnet{}
а затем у тебя есть три возможности:
1. Решение в лоб
class InvoiceForm
{
OnShow(){this.document.Load();...}
OnButtonSaveClick{this.document.Save();...}
private Invoice document;
}
2. Здесь ты как раз должен будешь пользовать dynamic_cast
class Form
{
OnShow(){this.document.Load();...}
OnButtonSaveClick{this.document.Save();...}
private Document document;
}
class InvoiceForm : Form
{
MyFunc(){Invoice invoice = (Invoice)document;...}
}
3. Дизайнерский финт Или, если интересно, шаблон GoF "Template Method".
abstract class Form
{
OnShow(){this.getDocument().Load();...}
OnButtonSaveClick{this.getDocument().Save();...}
abstract protected Document getDocument();
}
class InvoiceForm : Form
{
protected Document getDocument(){return document;}
private Invoice document;
}
Здравствуйте, Nicht, Вы писали:
N>Мне тут не очень понятен один аспект. N>Если у тебя OutDocument отображается в OutDocumentForm, а InDocument в InDocumentForm, то есть ли смысл засовывать в каждую из форм Document. Пусть каждая из них работает со своим подклассом Document. И никакого динамиккаста не будет. N>Или в этом есть какой — то потаенный смысл?
дело в том, что Document и DocumentForm — не "пустые" абстрактные классы. там реализована логика общая для обоих типов документов. соответственно на предлагаемое усложнение (переходя от статического связывания к динамическому) я пошел дабы избавиться от необходимости реализовывать одинаковую функциональность в двух парах In-InForm Out-OutForm.
в принципе, я допускаю, что в данном случае стоит задуматься о необходимости использования паттерна мост.
но другого паттерна в альтернативу я предложить не могу.
Здравствуйте, Mishka, Вы писали:
M>Здравствуйте, sapunidze, Вы писали:
S>>честно говоря не очень понимаю что дает введение данных классов...
M>Что ты хотел
Исхитрись-ка мне добыть
То-Чаво-Не-Может-Быть!
Запиши себе названье,
Чтобы в спешке не забыть! (с) Филатов
...другие варианты пропустил... (в виду того, что от этого наоборот уйти хотелось)
M>3. Дизайнерский финт Или, если интересно, шаблон GoF "Template Method". M>
M>abstract class Form
M>{
M> OnShow(){this.getDocument().Load();...}
M> OnButtonSaveClick{this.getDocument().Save();...}
M> abstract protected Document getDocument();
M>}
M>class InvoiceForm : Form
M>{
M> protected Document getDocument(){return document;}
M> private Invoice document;
M>}
M>
M>Третий вариант с моей точки зрения самый лучший.
Не печалься и не хнычь!
Стоит только кинуть клич!
Ну-ко станьте предо мною,
Тит Кузьмич и Фрол Фомич! () туда же...
Здравствуйте, sapunidze, Вы писали:
S>дело в том, что Document и DocumentForm — не "пустые" абстрактные классы. там реализована логика общая для обоих типов документов. соответственно на предлагаемое усложнение (переходя от статического связывания к динамическому) я пошел дабы избавиться от необходимости реализовывать одинаковую функциональность в двух парах In-InForm Out-OutForm.
S>в принципе, я допускаю, что в данном случае стоит задуматься о необходимости использования паттерна мост. S>но другого паттерна в альтернативу я предложить не могу.
На сколько мне известно, мост применяется когда нужно свести несколько одинаковых функциональностей с разным интерфейсом к одному интерфейсу.
Как я понял InDocument и OutDocument значительно отличаются по своим функциям. Так что скорее всего мост в чистом виде не подойдет.
Но можно попробовать придумать что — то типа загдушки. Для каждого вида документа своя. В конструктор этой заглушки подавать непосредственно определенный вид документа(ну или в самом документе определить метод, который бы ее выдавал) А на основе этой заглушки создавать уже DocumentForm, И все методы, которые новые, делегировать этой заглушке. В общем это очень на мост похоже.
Что — то типа этого:
public class DocumentGag
{
private Document doc;
public DocumentGag ( Document doc )
{
this.doc = doc;
}
public Document getDocument ()
{
return doc;
}
}
public abstract class Document
{
public void write()
{
//TODO:
}
}
public abstract class DocumentForm
{
private Document doc;
public DocumentForm ( Document doc )
{
this.doc = doc;
}
public writeDocument ()
{
doc.write();
}
}
public class InDocument extends Document
{
public void superInWrite ()
{
//TODO SUPER:
}
}
public class InDocumentGag extends DocumentGag
{
private InDocument doc;
public InDocumentGag ( InDocument doc )
{
super ( doc );
this.doc = doc;
}
public void superInWrite ()
{
doc.superInWrite();
}
}
public class InDocumentForm extends DocumentForm
{
private InDocumentGag gag;
public InDocumentForm ( InDocumentGag gag )
{
super( gag.getDocument() );
this.gag = gag;
}
public void superWriteDocument ()
{
gag.superInWrite();
}
}
тоже самое и для Out.
Тут конечно есть свои недостатки. Например дублирование ссылки на документ.
Здравствуйте, sapunidze, Вы писали:
S>(теоретический интерес ) S>а не является ли getDocument() "вырожденным" примером реализации Factory Method? S>или все таки раз нет порождения, знамо...?
Если совсем по науке, то нет. Этот метод не создаёт объекты классов, то есть и сам шаблон не является "порождающим".
Это точно Template Method, если читать функциональность этого класса следующим образом:
есть алгоритм, состоящий из двух шагов. Первый — получить документ, второй — сохранить его. Первый шаг может изменятся в зависимости от документа, потому следует поручить этот шаг подклассам.