【问题标题】:how to solve this code duplication + add another method如何解决此代码重复+添加另一种方法
【发布时间】:2011-08-08 14:57:09
【问题描述】:

我有 3 个课程:

class First {
    public void SetA(){ ... }
    public void SetB(){ ... }
    public void SetC(){ ... }
    public void SetD(){ ... }
    public void SetZ(){ ... }
}

class Second {
    public void SetC(){ ... }
    public void SetD(){ ... }
    public void SetE(){ ... }
    public void SetF(){ ... }
    public void SetX(){ ... }
}

class Third{
    public void SetA(){ ... }
    public void SetB(){ ... }
    public void SetE(){ ... }
    public void SetF(){ ... }
    public void SetY(){ ... }
}

如您所见,我使用相同的方法复制代码。
昨天我意识到有时我想在每个方法中添加另一个推荐。
所以我正在寻找一种方法来解决这两个问题。我想到的一种解决方案是:

  1. 创建接口:

    interface IAllMethods {
            void SetA();
            void SetB();
            void SetC();
            void SetD();
            void SetE();
            void SetF();
            void SetX();
            void SetY();
            void SetZ();
    }
    
  2. 创建默认实现:

    class DefaultAllMethods {
            public void SetA(){ ... }
            public void SetB(){ ... }
            public void SetC(){ ... }
            public void SetD(){ ... }
            public void SetE(){ ... }
            public void SetF(){ ... }
            public void SetX(){ ... }
            public void SetY(){ ... }
            public void SetZ(){ ... }
    }
    
  3. 使用装饰器模式创建另一个实现以添加额外的命令:

    class ExtraAllMethods {
            private IAllMethods _allMethods;
            public ExtraAllMethods (IAllMethods allMethods) {
                _allMethods=allMethods;
            }
            public void SetA(){ 
                _allMethods.SetA();
                extraMethod();
            }
            public void SetB(){ 
                _allMethods.SetB();
                extraMethod();
            }
            public void SetC(){ 
                _allMethods.SetC();
                extraMethod();
            }
            ..
            ..
            ..
    }
    
  4. 在 First、Second 和 Third 类中使用期望实现。例如:

    class Third{
        private IAllMethods  _allMethods;
        public Third(IAllMethods allMethods) {
            _allMethods=allMethods;
        }
        public void SetA(){ _allMethods.SetA(); }
        public void SetB(){ _allMethods.SetB(); }
        ..
        ..
        ..
    }
    

您如何看待这个解决方案?有没有更好的设计来满足这个需求?

更新
人们要求真正的业务,所以这里是: 我有 3 种传输类型:TransmissionA、TransmissionB、TransmissionC 每个传输都有许多参数(成员或属性)。例如,TransmissionA 有 WorkerId、CustomerId、MessageName 等。 TransmissionB 有 WorkerId 和 MessageName 但没有 CustomerId。 TransmissionC 有 WorkerId、CustomerId 但没有 MessageName。这些只是示例 - 在我的情况下,每个传输都有更多属性。每个属性都有 Set 方法。
现在有一个新的需求。在系统的某处有一个名为“更新任务”的选项。如果该选项为 ON,那么我需要在每个 Set 方法中更新相关任务。这就是我想到装饰器模式的原因。

【问题讨论】:

  • 你为什么使用方法而不是设置属性?
  • 只需声明一个带有方法的抽象类并继承该类。然后,您可以简单地覆盖该方法。如果该类不使用它,则不要调用它或覆盖它。
  • 这些类实际上可以互换吗?换句话说,它是否像狗和猫一样,虽然不同,但既能走路又能咬人?我试图确切地了解它们的作用以及它们之间的关系。
  • @Armen Tsirunyan - 我认为这些方法确实有所作为。我同意这是一个糟糕的设计。
  • 如果您解释您要解决的问题,而不是给出抽象并询问“如何使其更抽象”,这将有所帮助。它使我们能够跳出框框思考。

标签: c# .net design-patterns architecture


【解决方案1】:
  1. 接口不是一个好主意,因为它的实现者只为接口提供的方法的子集提供功能。
  2. 这里不能使用decorator pattern,因为它是用来添加功能的,不能像添加方法那样用来改变API。请参阅this answer 了解更多信息。
  3. 如果你在不同的类中有相同的方法和相同的代码,这应该被提取到自己的类中,并由其他类使用。目前,您的课程很可能违反了single responsible principle

【讨论】:

  • 1.该接口在这里用于装饰器。 2.我使用装饰器是为了在每个方法中添加额外的命令(如日志命令),而不是添加方法。 3. 你能在这个例子中告诉我如何将这些类提取到一个类中吗? 4. 其他类的相同方法之间没有关系。
  • @Naor:正如其他人已经指出的那样:您的“示例代码”没有多大用处,因为它是抽象的。如果你在不同的类中有相同的代码,这是一个设计缺陷。如何解决它取决于您的实际代码库。关于你的答案:装饰器应该实现与被装饰对象相同的接口,即FirstSecondThird 应该实现IAllMethods。这直接说明接口是“错误的”,因为这三个类都没有提供接口的所有方法。这也取消了您展示的装饰器方法的资格。
  • @Naor:要接收非理论答案,请提供实际代码。
  • 我知道存在差距——First、Second 和 Third 不会实现 IAllMethods。我正在寻找更好的方法。例如,其他人建议为每个属性创建一个接口。请查看我添加的更新。
【解决方案2】:

这将起作用,但不是引入包含所有方法的全知接口和基本实现类(因此了解您的全部方法集合),您还可以采用更精细的方法并只制作一个接口以及每种方法的基本实现。这将更具可扩展性,如果您正确设置,您可以以类似插件的方式轻松附加它们。

【讨论】:

  • 你怎么能想象没有多重继承的每个方法的基本实现?
  • @mtijn:你的意思是我应该添加9个接口和实现(在这个例子中)?
  • 是和不,我在想 9 个接口和 9 个具有特定实现的类,我在想你的第一、第二和第三类通过调用具有实际的接口实现。您是否希望 First、Second 和 Third 通过继承或保留受支持插件的公共集合显式公开其功能取决于您。
【解决方案3】:

您可以为每个单独的方法定义一个接口,并为每个接口定义一个默认实现,并使您的类只实现需要的接口,并通过带有默认实现的构造函数进行参数化来装饰。

【讨论】:

    【解决方案4】:

    取决于这些方法在做什么,因此解决方案可能会有所不同。 但是,如果这些方法没有以某种方式在逻辑上相互关联,我建议通过类似的接口抽象每个方法

        interface ILogicBAware
        {
          void DoB();
        }
    
        interface ILogicCAware
        {
          void DoC();
        }
    
        interface IAllMethods : ILogicBAware, ILogicCAware
        {
           void DoAll();
        }
    

    通过这种方式,您可以获得更大的灵活性和更少的耦合。通过这种方式,您可以继续前进并决定如何封装实际逻辑。但这又取决于你提供的类和方法的底层是什么......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-25
      • 1970-01-01
      • 2023-02-05
      • 2017-02-15
      相关资源
      最近更新 更多