Каким образом вы реализуете специфическую для типа функциональность, когда использование полиморфизма НЕ имеет смысла? - PullRequest
2 голосов
/ 19 января 2011

Общий красный флаг, указывающий на то, что язык ООП не используется должным образом, выглядит следующим образом:

if (typeof(x) == T1)
{
    DoSomethingWithT1(x);
}
else if (typeof(x) == T2)
{
    DoSomethingWithT2(x);
}

Стандартное "исправление" для таких проблем проектирования состоит в том, чтобы сделать T1 и T2 обеинтерфейс, либо через наследование базового типа, либо через реализацию общего интерфейса (на языках, которые его поддерживают);например, в C # решение может быть следующим:

public interface IT
{
    void DoSomething();
}

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

Например, рассмотрим случай пользовательского интерфейса, который обеспечивает представление данного скопления данных.Предположим, что это представление способно отображать различные макеты и элементы управления в зависимости от типа представляемых данных. Как бы вы реализовали этот специфичный для типа рендеринг без набора операторов if / else?

По причинамчто я надеюсь очевидны, в этом случае использование логики рендеринга в самом типе кажется мне очень плохим решением.С другой стороны, не связывая тип объекта данных с его визуальным представлением, мне трудно понять, как избежать сценария if / else.

Вот конкретный пример: я работаю надторговое приложение, которое использует множество различных моделей ценообразования для различных рыночных продуктов.Эти разные модели представлены типами, унаследованными от общей базы PricingModel;и каждый тип связан с совершенно другим набором параметров.Когда пользователь хочет просмотреть параметры для конкретной модели ценообразования (для конкретного продукта), в настоящее время они отображаются в форме, которая определяет тип модели и отображает соответствующий набор элементов управления.Мой вопрос заключается в том, как это может быть реализовано более элегантно, чем сейчас (с большим блоком if / else).

Я понимаю, что это, вероятно, кажется очень простым вопросом;это лишь один из тех пробелов в моих знаниях (о твердых принципах ООП, шаблонах проектирования, здравом смысле?), которые я решил, что пора исправить.

Ответы [ 3 ]

1 голос
/ 19 января 2011

Мы внедряем (Spring.Net) такую ​​функциональность в словари по типу.

IDictionary<Type, IBlahImplementor> blahImplementors;

blahImplementors[thingy.GetType()].Do(thingy);

Этот словарь может управляться своего рода хранилищем, которое предоставляет эту функциональность.

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

interface IBlahImplementor
{
  Type ForType { get; }

  void Do(object thingy);
}

Затем он добавляется в словарь следующим образом:

IEnumerably<IBlahImplementor> blahImplementors;
foreach (var implementor in blahImplementors)
{
  blahImplementors.Add(implementor.ForType, implementor);
}

ПримечаниеИМХО, очень важно понимать, что некоторые вещи НЕ принадлежат классу, даже если предоставление реализаций подтипа значительно упростит жизнь.


Редактировать : Наконецпонял ваш конкретный пример.

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

interface IPricingModelUiConfigurer
{
  Type PricingModelType { get; }
  void SetupUi(Control parent, IPricingModel model);
}
0 голосов
/ 20 января 2011

вы можете использовать общий подход к интерфейсу, как вы описываете, и шаблон Command для запуска методов с «функциональностью, не относящейся к типу этого объекта».Я думаю, что это не сломает твердые принципы ООП.

0 голосов
/ 19 января 2011

То, что вы описали, в значительной степени точно соответствует сценарию использования Шаблон посетителя .

РЕДАКТИРОВАТЬ : Для вашего конкретного примера вы можете применить шаблон посетителя какэто:

// interface used to add external functionality to pricing models
public interface PricingModelVisitor {
    void visitPricingModel1(PricingModel1 m);
    void visitPricingModel2(PricingModel2 m);
    ...
}
// your existing base-class, with added abstract accept() method to accept a visitor
public abstract class PricingModelBase {
    public abstract void accept(PricingModelVisitor v);
    ...
}
// concrete implementations of the PricingModelBase implement accept() by calling the 
// appropriate method on the visitor, passing themselves as the argument
public class PricingModel1 : PricingModelBase { 
    public void accept(PricingModelVisitor v) { v.visitPricingModel1(this); }
    ...
}
public class PricingModel2 : PricingModel {
    public void accept(PricingModelVisitor v) { v.visitPricingModel2(this); }
    ...
}
// concrete implementation of the visitor interface, in this case with the new 
// functionality of adding the appropriate controls to a parent control
public class ParameterGuiVisitor : PricingModelVisitor {
    private Control _parent;
    public ParameterGuiVisitor(Control parent) { _parent = parent; }
    visitPricingModel1(PricingModel1 m) {
        // add controls to _parent for PricingModel1
    }
    visitPricingModel2(PricingModel2 m) {
        // add controls to _parent for PricingModel1
    }
}

теперь, вместо использования большого блока if - else, когда вам нужно отобразить элементы управления для редактирования параметров определенного подтипа PricingModelVisitor, вы можете простопозвоните

somePricingModel.accept(new ParameterGuiVisitor(parentControl))

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...