Лучший способ решить, какой подкласс нужен

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

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

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

CheckoutContext chooseSubclass(CheckoutCase c)
{
CheckoutContext output;
switch (c):
{
  case CheckoutCase.SingleItemNew:
    output = new SingleItemNew;
    break;
  case . . . 
  return output;
}
}

5 ответов

Решение

Если есть большое количество случаев, я бы создал Dictionary<CheckoutCase, Type> и заполните его один раз набором всех значений CheckoutCase и соответствующих типов CheckoutContext. Тогда вы могли бы использовать Activator.CreateInstance для возврата соответствующего типа вместо гигантского оператора switch.

То, что вы реализуете - это фабричный шаблон. Это стандартная практика, хотя обычно это означает написание большого количества повторяющегося кода (во многом аналогично вашему выражению switch, которое часто так и реализуется). Вы можете делать всякие причудливые вещи, такие как динамическое создание экземпляров посредством отражения, но не играйте с огнем. Просто придерживайтесь инструкции switch, и все будет в порядке.

Вы можете реализовать это с помощью пользовательского атрибута и фабричного метода. Сделайте так, чтобы все ваши подклассы реализовали CustomAttribute, скажем, CheckOutCaseScenarioAttribute, который принимает значение Enum CheckOutCase.

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

Это называется шаблоном фабричного дизайна. Я хотел бы создать статический метод, который возвращает необходимый класс. Хорошей практикой здесь является реализация интерфейса и возврат интерфейса.

interface ICheckoutItem
{
    void CheckOut();
}

Пусть ваши предметы реализуют интерфейс. Затем в вашем заводском методе верните интерфейс каждого элемента.

ICheckoutItem chooseSubclass(CheckoutCase c)
{
ICheckoutItem output;
    switch (c):
    {
       case CheckoutCase.SingleItemNew:
         output = new SingleItemNew;
         break;
       case . . . 
  return output;
    }
}

Вы можете создать атрибут, который имеет одно свойство, которое будет иметь тип CheckoutContext:

public class CheckoutContextAttribute : Attribute
{
   public Type CheckoutType{get;set;}
}

Затем в вашем перечислении вы можете поместить правильный атрибут в правильный тип перечисления:

public enum CheckoutCase
{
   [CheckoutContext(CheckoutType=typeof(SingleItemNew)]
   SingleItemNew,
   ...
   ...
}

Затем в этом методе, где вам нужно отправить обратно правильный тип контекста, вы используете отражение и делаете что-то вроде этого:

public CheckoutContext GetContext(CheckoutCase c)
{
   FieldInfo field = c.GetType().GetField(c.ToString());
   object[] attribs = field.GetCustomAttributes(typeof(CheckoutContextAttribute),false);
   CheckountContext result = null;
   if(attribs.Length > 0)
   {
      CheckoutContextAttribute attrib = attribs[0] as CheckoutContextAttribute;
      Type type = attrib.CheckoutType;
      result = Activator.CreateInstance(type) as CheckountContext;
   }

   return result;
}

Это должно сделать свое дело. Просто добавьте проверку нуля / ошибок, чтобы быть в безопасности.

Другие вопросы по тегам