Шаблон проектирования “Посреднический набор определений” — хорошо известен под другим названием?

StackOverflow https://stackoverflow.com/questions/401720

Вопрос

В проекте, которым я занимаюсь уже много лет, я постепенно разработал шаблон проектирования, который оказался для меня чрезвычайно полезным.Иногда я чувствую, что мне следовало бы стать немного евангелистом, но я был бы немного смущен, если бы попытался и обнаружил, что это всего лишь моя версия чьей-то старой шляпы.Я перерыл все Шаблоны проектирования тщетно искал это, и я не встречал никого, кто бы еще говорил об этом, но мой поиск не был исчерпывающим.

Основная идея заключается в создании объекта-посредника, который управляет набором объектов определения, причем каждый объект определения представляет собой возможное значение некоторого сложного свойства.В качестве примера у вас могут быть классы Car, Plane и Generator, все из которых имеют EngineType .Car не хранит свой собственный объект EngineType, он хранит некоторый ссылочный ключ, который указывает тип двигателя, который у него есть (например, целое число или строковый идентификатор).Когда мы хотим посмотреть на свойства или поведение EngineType, скажем WankelEngine, мы запрашиваем у одноэлементного объекта EngineTypeBroker объект определения WankelEngine, передавая ему ссылочный ключ.Этот объект инкапсулирует все, что интересно знать о EngineTypes, возможно, просто являясь списком свойств, но потенциально также имея загруженное в него поведение.

Итак, что это облегчает, так это своего рода общую слабо связанную агрегацию, где многие автомобили могут иметь WankelEngine, но существует только один объект определения WankelEngine (и EngineTypeBroker может заменить этот объект, используя слабую связь для улучшения морфизма времени выполнения).

Некоторые элементы этого шаблона в том виде, в каком я его использую (продолжая использовать EngineType в качестве примера):

  1. Всегда существуют функции IsEngineType(x) и EngineType(x) для определения, является ли данное значение допустимым ссылочным ключом для EngineType и для извлечения объекта определения EngineType, соответствующего ссылочному ключу, соответственно.
  2. Я всегда допускаю несколько форм ссылочного ключа для данного EngineType, всегда, по крайней мере, строковое имя и сам объект определения, чаще всего целочисленный идентификатор, а иногда и типы объектов, которые объединяют EngineType.Это помогает при отладке, делает код более гибким и, в моей конкретной ситуации, устраняет множество проблем с обратной совместимостью по сравнению со старыми практиками.(Обычный способ, которым люди делали все это в контексте этого проекта, заключался в определении хэшей для каждого свойства, которое может иметь EngineType, и поиске свойств по ссылочному ключу.)
  3. Обычно каждый экземпляр определения является подклассом общего класса для данного типа определения (т. е.WankelEngine наследует EngineType).Файлы классов для объектов определения хранятся в каталоге типа /Def/EngineType (т. е.Классом WankelEngine будет /Def/EngineType/WankelEngine).Таким образом, связанные определения сгруппированы вместе, и файлы классов напоминают файлы конфигурации для EngineType, но с возможностью определения кода (обычно не встречается в файлах конфигурации).

Какой-нибудь тривиально иллюстрирующий пример псевдокода:

class Car {

    attribute Name;
    attribute EngineTypeCode;

    object GetEngineTypeDef() {
        return EngineTypeBroker->EngineType(this->GetEngineTypeCode());
    }

    string GetDescription() {
        object def = this->GetEngineTypeDef();
        return "I am a car called " . this->GetName() . ", whose " .
            def->GetEngineTypeName() . " engine can run at " .
            def->GetEngineTypeMaxRPM() . " RPM!";
    }

}

Итак, есть ли какое-нибудь название для этого?

Это было полезно?

Решение

Единая регистрация

Веришь мне или нет.Я думал о том же самом сегодня утром.

Я использовал этот шаблон раньше, но я никогда не находил ссылки на него и не знаю, как его назвать.

Я думаю, что это своего рода синглтон с ключом, где экземпляры где-то хранятся и они получены с помощью ключа.

Последний раз, когда я использовал его, это было для извлечения данных из разных источников.

У меня было около 50 таблиц базы данных (пусть будет 10), и у меня есть интерфейсная "таблица", где должны были отображаться данные, но данные могли поступать из любого из этих источников, и для каждого из них требовалась разная логика (запросы, объединения, ключи и т.д.)

Этот интерфейс был "настраиваемым", поэтому я не мог знать, какие значения должны были отображаться, а какие другие - нет.

Решение состояло в том, чтобы взять ColumnName (во внешнем интерфейсе ) в качестве ключа и получить правильный экземпляр для создания правильного запроса.

Это было установлено в хэш-карте в начале, а позже извлечено из таблицы базы данных.

Код был примерно таким:

class DataFetcher {
    abstract Object getData( Object id );
}

class CustomerNameDataFetcher extends DataFetcher {
    Object getData( Object customerId ) { 
        // select name from customer where id = ? 
     }
}

class CompanyAdressDataFetcher extends DataFetcher { 
     Object getData( Object customerId ) { // don't ask why.
          // select name from company , customer where customer.co = company.co and cu = ?  etc.
     }
} 

class ProductColor extends DataFetcher { 
     Object getData( Object x ) { 
     // join from customer to color, to company to season to a bunch of table where id = ? 
}

// And the list goes on.

Каждый подкласс использовал разную логику.

Во время выполнения пользователь настроил его просмотр и выбрал то, что он хочет видеть.

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

Все средства выборки данных были установлены в родительском классе (я не хотел иметь отдельный класс для этого) в методе класса.

class DataFetcher {
    abstract Object getData( Object id );

    private static final Map fetchers = new HashMap();static { 
        fetchers.put("customer.name", new CustomerNameDataFetcher() );
        fetchers.put("company.address", new CompanyAdressDataFetcher () );
        fetchers.put("product.color", new ProductColor () );
        ...
    }
    public static DataFetcher getFetcher( String id ) { 
        return fetchers.get( id );
    }      

}

В конце, чтобы заполнить таблицу переднего плана, я просто называю ее так:

псевдокод

 for each row in table 
      for each column in row
          column.text = DataFetcher.getFetcher( column.id ).getData( row.id )
       end
 end

Неужели это так?Или я неправильно истолковал ваше описание, а мое совсем другое.

Наконец, я думаю, что это называется SingletonRegistry или что-то в этом роде.Я (вероятно), как и вы, создал это по необходимости.Скорее всего, это обычная схема.

Другие советы

Я уже использовал шаблон, похожий на этот, чаще всего в играх.У меня были бы классы WeaponDefinition и WeaponInstance (не совсем с этими именами).Класс WeaponDefinition (и различные подклассы, если у меня есть разные типы оружия, напримерближний бой против снаряда) отвечал бы за отслеживание глобальных данных для данного типа оружия (скорострельность, максимальный боезапас, название и т.д.) и обладал бы всей логикой.Класс WeaponInstance (и подклассы) содержат текущее состояние в последовательности стрельбы (для использования при сравнении скорострельности), текущее количество боеприпасов и указатель (это может быть некоторый ключ к классу manager, как в вашем примере, но это, похоже, не является требованием шаблона) на WeaponDefinition.WeaponInstance имеет множество функций для стрельбы, перезарядки и т.д., которые просто вызывают соответствующий метод в экземпляре WeaponDefinition, передавая себя в качестве аргумента.Это означает, что элементы определения оружия не дублируются для каждого танка / солдата / самолета в игровом мире, но у всех них есть свое количество боеприпасов и т.д.

Я понятия не имею, как это называется, и я не уверен, что это совсем то же самое, о чем вы говорите, но я думаю, что это близко.Это определенно полезно.

Для меня это звучит как сочетание GoF Builder, Prototype и, возможно, Полулегкого веса.

Это звучит как разновидность легкого веса (у многих автомобилей общий двигатель Wankel).Но какой в этом смысл?У большинства автомобилей есть двигатель, но как многие из них могут иметь один и тот же экземпляр двигателя?Таким образом, они далеко не уйдут.Или вы имеете в виду, что многие автомобили имеют двигатель типа WankelEngine?Предположим, в этом больше смысла.Тогда какая польза от "объекта определения WankelEngine"?Это фабрика, которая создает варианты этого объекта и передает их обратно отправителю запроса?Если это так, то это звучит не как объект определения, а скорее как Фабрика, которая принимает параметры объекта для сборки и возвращает этот объект обратно.

Я вижу здесь несколько хороших практик GoF, в частности, которые вы создаете, а не наследуете (у моей машины есть двигатель противдвигатель моей машины - WankelEngine).Жаль, что я не могу точно вспомнить цитату, но это что-то вроде "наследование нарушает инкапсуляцию" и "предпочтение композиции перед наследованием".

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

Ребята из GoF обсуждают объединение шаблонов в более крупные шаблоны, в частности, MVC - это совокупность трех других шаблонов.Похоже, ты уже делал что-то подобное.

Это немного похоже на Service Locator, в котором ваши полулегковесы регистрируются как одиночки.

То, что у вас есть, - это карта, она же Словарь.У вас просто есть уникальная изюминка, если несколько ключей сопоставлены с одним объектом.

Почему это карта:

  • храните ключ
  • Используйте ключ для запроса значения из некоторой структуры данных.

Вы можете найти реализации в:

  • STL (включает:карта)
  • Java (импорт:java.util.Словарь)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top