→ Пошук по сайту       Увійти / Зареєструватися
Знання Патерни Структурні патерни — Structural patterns

8. Компонувальник — Composite

8.	Компонувальник — Composite

Чи ви коли небуть задумувалися над тим, чому так багато речей у цьому світі мають деревовидну структуру? Адміністративний устрій країни для прикладу, або ж ваша організація. Топ-менеджмент компанії може делегувати роботу менеджерам відділів, які, відповідно, делегують її до ваших прямих менеджерів, а ті, в свою чергу, дадуть вам якусь роботу.

Або для прикладу, XML має деревовидну структуру. Мабуть тому, що це найкращий спосіб зберегти дані, що можуть містити дані, які в свою чергу можуть мітити дані, які... Отже, припустимо, що вам слід зкомпонувати якийсь складний документ із частин. Деякі частини вміють збирати дані (GatherData), базуючить на відповідній ID-шці. Деякі частини просто утримують інші частини. Ми побудуємо XML «кустарним» способом у цьому прикладі.
Компонувальник дозволяє нам зберігати деревовидну структуру і працювати однаково із батьками та синами у дереві.

Уривок коду 8.1. інтерфейс що визначає спільні вимоги до батьків і дітей (:

 interface IDocumentComponent
{
    string GatherData();
    void AddComponent(IDocumentComponent documentComponent);
}

А тепер реалізація одного із листків у нашому дереві –CustomerDocumentComponent, яка вміє збирати кусок XML, базуючись на ID-шці замовника.

Уривок коду 8.2. Реалізація «листкового» компонента

 class CustomerDocumentComponent : IDocumentComponent
{
    private int CustomerIdToGatherData { get; set; }
    public CustomerDocumentComponent(int customerIdToGatherData)
    {
        CustomerIdToGatherData = customerIdToGatherData;
    }
    public string GatherData()
    {
        string customerData;
        switch (CustomerIdToGatherData)
        {
            case 41:
                customerData = "Andriy Buday";
                break;
            default:
                customerData = "Someone else";
                break;
        }
        return string.Format("<Customer>{0}</Customer>", customerData);
    }
    public void AddComponent(IDocumentComponent documentComponent)
    {
        Console.WriteLine("Cannot add to leaf...");
    }
}

А тепер реалізація нелисткових компонентів нашого дерева. Зверніть увагу, що в методі GatherData ми просто ітеруємо по всіх нащадках і викликаємо наш основний метод для збору даних.

Уривок коду 8.3. Компонент, що містить інші компоненти

 class DocumentComponent : IDocumentComponent
{
    public string Name { get; private set; }
    public List<IDocumentComponent> DocumentComponents { get; private set; }
    public DocumentComponent(string name)
    {
        Name = name;
        DocumentComponents = new List<IDocumentComponent>();
    }
    public string GatherData()
    {
        var stringBuilder = new StringBuilder();
        stringBuilder.AppendLine(string.Format("<{0}>", Name));
        foreach (var documentComponent in DocumentComponents)
        {
            documentComponent.GatherData();
            stringBuilder.AppendLine(documentComponent.GatherData());
        }
        stringBuilder.AppendLine(string.Format("</{0}>", Name));
        return stringBuilder.ToString();
    }
    public void AddComponent(IDocumentComponent documentComponent)
    {
        DocumentComponents.Add(documentComponent);
    }
}

Уривок коду 8.3. Клеїмо частинки докупи – процес компонування документу

 var document = new DocumentComponent("ComposableDocument");
var headerDocumentSection = new HeaderDocumentComponent();
var body = new DocumentComponent("Body");
document.AddComponent(headerDocumentSection);
document.AddComponent(body);

var customerDocumentSection = new CustomerDocumentComponent(41);
var orders = new DocumentComponent("Orders");
var order0 = new OrderDocumentComponent(0);
var order1 = new OrderDocumentComponent(1);
orders.AddComponent(order0);
orders.AddComponent(order1);

body.AddComponent(customerDocumentSection);
body.AddComponent(orders);

string gatheredData = document.GatherData();

Console.WriteLine(gatheredData);

Вивід, певно, схожий на XML. Принаймні я хотів щоб він був таким.

Вивід:

 <ComposableDocument>
  <Header>
     <MessageTime>8:47:23</MessageTime>
  </Header>
  <Body>
    <Customer>Andriy Buday</Customer>
    <Orders>
      <Order>Kindle;Book1;Book2</Order>
      <Order>Phone;Cable;Headset</Order>
    </Orders>
  </Body>
</ComposableDocument>

Варто додати, що «GoF-хлопці» пропонують також методи Remove(Component) та GetChild(int) у інтерфейсі компоненту, тому, можливо, вам захочеться їх добавити. Одне хочу сказати - ніколи не зациклюєйтися на якихось прикладах і однотипних поясненнях. Ваші потреби можуть дещо відрізнятися від того, що описано в класичному дизайн патерні, але в той же час ваша не класична реалізація вам ідеально буде підходити. Можливо у вас якесь вироджене або ускладнене застосування, зазвичай воно завжди так і є.

По матеріалам книги Андрія Будая "Дизайн патерни – просто, як двері". Матеріал розміщується за домовленістю з автором.
Робота представлена за умовами ліцензії Creative Commons Attribution-NonCommercial 3.0 Unported License.

загрузка...
Сторінки, близькі за змістом