【问题标题】:Best way to decide which subclass is needed决定需要哪个子类的最佳方法
【发布时间】:2009-06-10 15:23:39
【问题描述】:

我正在为当前项目开发一个大型结账应用程序。 此结帐有很多情况,具体取决于用户的管理员级别、他们如何结帐以及他们要结帐的项目类型,因此该过程通​​过一组上下文类从 .aspx 页面中抽象出来。

这些类都是单个类 CheckoutContext 的子类,并且要使用的类的类型通过枚举来注明。

有没有类似于 typedef 的东西我可以用来选择使用哪个子类,或者我应该只是有一个返回相关类的方法,像这样:

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

【问题讨论】:

  • 您需要多动态?我的意思是,您多久添加一次新的子类,是否需要在不重新编译应用程序的情况下对其进行配置?您是否有多个开发人员创建这些子类?如果您要处理多个此类需求,您可能需要更强大的解决方案。如果没有,请坚持使用开关。
  • 这一点的全部要点是结帐过程太复杂,无法逐节处理,我们需要每页大约 15 个方法来处理哪些字段可用.因此,我们将流程分成类。很有可能以后会做更多,所以我想要一个不需要额外努力来添加结帐流程的解决方案。

标签: c# enums subclassing


【解决方案1】:

您正在实施的是Factory Pattern。这是一种标准做法,尽管它通常意味着编写大量重复代码(很像您的 switch 语句,这通常是它们的实现方式)。你可以做各种花哨的事情,比如通过反射进行动态实例化,但不要玩火。只要坚持 switch 语句,你会没事的。

【讨论】:

    【解决方案2】:

    如果有大量案例,我会创建一个Dictionary<CheckoutCase, Type> 并使用所有 CheckoutCase 值和相应的 CheckoutContext 类型的集合填充一次。然后您可以使用 Activator.CreateInstance 来返回适当的类型,而不是巨大的 switch 语句。

    【讨论】:

    • 我最终还是选择了这个版本,案例太难读了!
    【解决方案3】:

    您可以使用自定义属性和工厂方法来实现它。让所有子类实现一个 CustomAttribute,比如 CheckOutCaseScenarioAttribute,它采用 CheckOutCase Enum 值。

    在您的工厂方法中,查找设置了此枚举值的类型并创建对象。这将避免您的开关盒。如果您的工厂方法中没有任何其他初始化逻辑,这将起作用。

    【讨论】:

      【解决方案4】:

      这称为工厂设计模式。我将创建一个返回所需类的静态方法。这里的一个好的做法是实现一个接口并返回该接口。

      interface ICheckoutItem
      {
          void CheckOut();
      }
      

      让您的项目实现接口。然后在你的工厂方法中返回每个项目的接口。

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

      【讨论】:

      • 返回接口而不是基类有什么好处?如果没有优势,则此答案与当前解决方案相同。
      • 我写这个是因为其他人在我上面写了当前的答案。事实上我什至赞成他的答案。接口更好,因为您可能拥有最终不会从同一个基类继承但仍需要“签出”的项目,此时您将需要最少的重构,因为您的方法和逻辑将不依赖于特定的类。
      【解决方案5】:

      您可以创建一个具有一个属性的属性,该属性将是 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;
      }
      

      这应该可以解决问题。只需添加一些空/错误检查以确保安全。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-08
        • 2015-02-27
        • 1970-01-01
        • 2016-04-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多