Проблема проектирования: получить информацию о типе дочернего объекта, избегая операторов if на уровне представления - PullRequest
1 голос
/ 12 марта 2009

У меня есть иерархия клиентов:

abstract class Customer {
    public virtual string Name { get; set; }
}

class HighValueCustomer : Customer {
    public virtual int MaxSpending { get; set; }
} 

class SpecialCustomer : Customer {
    public virtual string Award { get; set; }
}

Когда я получаю Заказчика, я хотел бы показать в веб-форме свойства для редактирования / изменения. В настоящее время я использую операторы if, чтобы найти дочерний тип клиента и показать специализированные свойства. Есть ли шаблон дизайна (посетитель?) Или лучший способ, чтобы я мог избежать «если» на уровне представления? Как ты это делаешь?

Дополнительная информация: Это сайт asp.net с бэкэндом nHibernate. У каждого типа клиента есть свой пользовательский элемент управления на странице, который я хотел бы загрузить автоматически, учитывая тип клиента.

Ответы [ 4 ]

2 голосов
/ 12 марта 2009

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

2 голосов
/ 12 марта 2009

Можете ли вы использовать отражение, чтобы получить список свойств, относящихся к подклассу (экземпляру)? (Менее подвержен ошибкам.)

Если нет, создайте (виртуальный) метод, который возвращает специальные свойства. (Больше ошибок!)

Для примера последнего:

abstract class Customer {
    public virtual string Name { get; set; }

    public virtual IDictionary<string, object> GetProperties()
    {
        var ret = new Dictionary<string, object>();
        ret["Name"] = Name;
        return ret;
    }
}

class HighValueCustomer : Customer {
    public virtual int MaxSpending { get; set; }

    public override IDictionary<string, object> GetProperties()
    {
        var ret = base.GetProperties();
        ret["Max spending"] = MaxSpending;
        return ret;
    }
} 

class SpecialCustomer : Customer {
    public virtual string Award { get; set; }

    public override IDictionary<string, object> GetProperties()
    {
        var ret = base.GetProperties();
        ret["Award"] = Award;
        return ret;
    }
}

Вы, вероятно, хотите создать разделы (fieldset s?) На своей веб-странице, так или иначе, поэтому в игру вступит if, что сделает этот дополнительный код раздражающим и бесполезным.

0 голосов
/ 12 марта 2009

новый:

interface CustomerEdit
{
    void Display();
}

редактирование:

abstract class Customer {
    protected CustomerEdit customerEdit; // customers have an object which allows for edit

    public virtual string Name { get; set; }
    public void Display() { customerEdit.Display(); } // allow the CustomerEdit implementor to display the UI elements
}

// Set customerEdit in constructor, tie with "this"
class HighValueCustomer : Customer {
    public virtual int MaxSpending { get; set; }
} 

// Set customerEdit in constructor, tie with "this"
class SpecialCustomer : Customer {
    public virtual string Award { get; set; }
}

использование:

Customer whichCouldItBe = GetSomeCustomer();
whichCouldItBe.Display(); // shows UI depeneding on the concrete type
0 голосов
/ 12 марта 2009

Вы пробовали что-то вроде этого:

public class Customer<T>
    where T : Customer<T>
{
    private T subClass;
    public IDictionary<string, object> GetProperties()
    {
        return subClass.GetProperties();
    }
}

С подклассом:

public class FinancialCustomer : Customer<FinancialCustomer>
{
}

Это не в моей голове, поэтому может не сработать. Я видел этот тип кода в CSLA.NET. Вот ссылка на класс CSLA.NET с именем BusinessBase.cs , определение которого аналогично приведенному выше.

...