Лучший способ решить, какой подкласс нужен
Я работаю над крупномасштабным приложением для оформления заказа для текущего проекта. Эта проверка имеет много случаев в зависимости от уровня администратора пользователя, от того, как он попал на проверку, и какой тип элемента он проверяет, и поэтому процесс абстрагируется от страниц.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;
}
Это должно сделать свое дело. Просто добавьте проверку нуля / ошибок, чтобы быть в безопасности.