除了成员函数和继承之外,向 class 添加功能的一些最常见的编程模式是什么?

Excluding member functions and inheritance, what are some of the most common programming patterns for adding functionality to a class?

解决此问题的广泛使用方法可能不超过 2-4 种。

我有一个常见的 class 我到处都在使用,并且(有时)我想赋予它特殊的能力。为了争论起见,假设类型检查不是必需的。

有哪些方法可以为 class 提供功能而不是简单的继承或成员函数?

  1. 我见过的一种方式是 "decorator" 模式,其中一种变异器环绕 class,稍微修改它,并吐出一个版本功能更多

  2. 我读过但从未使用过的另一个是用于游戏的。它与实体和power-ups/augments有关。我不确定具体细节,但我认为他们有一份清单。

  3. ???

我不需要特定语言的特定代码,只需要一般要点和一些关键字。我可以从那里实施。

据我所知,向 class 添加函数有点像空操作。有很多方法,但它似乎总是变得丑陋,因为 class 本来就是它自己,而不是其他任何东西。

更容易理解的是将对函数的引用添加到对象或映射。

据我了解,您希望扩展一个接口以允许可能需要额外功能的特定于客户端的实现,并且您希望以一种不会弄乱基础的方式进行class.

如您所述,对于简单系统,标准方法是使用适配器模式:subclass the "special abilities",然后在需要时调用特定的 subclass .如果您需要添加的特殊能力的范围已知且相当小,这绝对是最佳选择,即您通常只使用基础 class,但对于三到五个需要额外功能的地方需要。

但我明白您为什么想要一些其他可能的选项,因为我们很少预先知道子classes 所需的附加功能的全部范围(即,当实现连接 API 或组件 Class,它们中的每一个都几乎可以无限扩展)。根据特定于客户端的实现的复杂程度、需要多少附加功能以及实现之间的差异有多大,可以通过多种方式解决这个问题:

  • 您提到的装饰器模式(在特殊实体仅扩展基 class 的现有方法而不添加全新方法的情况下很有用)

    class MyClass{};
    DecoratedClass = decorate(MyClass);
    
  • 子classes 的组合 AbstractFactory/Adaptor 构建器(对于子classes 中的功能分组可能不同的情况很有用他们的实现)

    interface Button { 
        void paint(); 
    }

    interface GUIFactory { 
        Button createButton(); 
    }

    class WinFactory implements GUIFactory { 
        public Button createButton() { 
            return new WinButton(); 
        } 
    }

    class OSXFactory implements GUIFactory {
        public Button createButton() { 
            return new OSXButton(); 
        } 
    } 

    class WinButton implements Button { 
        public void paint() {
            System.out.println("I'm a WinButton"); 
        } 
    } 

    class OSXButton implements Button { 
        public void paint() { 
            System.out.println("I'm an OSXButton"); 
        } 
    } 

    class Application { 
        public Application(GUIFactory factory) { 
            Button button = factory.createButton();
            button.paint(); 
        }
     }

    public class ApplicationRunner { 
        public static void main(String[] args) { 
            new Application(createOsSpecificFactory()); 
        }

    public static GUIFactory createOsSpecificFactory() {
        int sys = readFromConfigFile("OS_TYPE");
        if (sys == 0) return new WinFactory(); 
        else return new OSXFactory(); 
        }
    }
  • Strategy pattern 也可以工作,具体取决于用例。但是,对于您不想更改的现有基础 class,这将是一个更重的提升,这取决于它是否是在这些子 class 之间发生变化的策略。访问者模式也适用,但会遇到同样的问题,并且涉及对基础架构的重大更改 class.

    class MyClass{
      public sort() { Globals.getSortStrategy()() }
    };
    
  • 最后,如果所需的 "special abilities" 足以(或最终可能足以)证明全新界面的合理性,那么现在可能是使用 Extension Objects Pattern.尽管它确实使您的客户或子class变得复杂得多,因为他们必须管理更多:检查特定扩展对象及其所需方法是否存在,等等。

    class MyClass{
      public addExtension(addMe) {
        addMe.initialize(this);
      }
      public getExtension(getMe);
    };
    (new MyClass()).getExtension("wooper").doWoop();
    

话虽这么说,但要尽可能简单,有时您只需编写特定的子classes 或一些适配器就大功告成了,尤其是对于预先存在的 class 在许多其他地方使用。您还必须询问您希望将 class 保留多少以进一步扩展。通过抽象工厂保持较低的技术债务可能是值得的,因此当您在未来添加更多功能时需要进行更少的更改。或者,为了便于理解和简单起见,您真正想要的是锁定 class 以防止进一步扩展。您必须检查您的用例、未来计划和现有架构,以决定前进的道路。更有可能的是,有很多正确的答案,只有几个非常错误的答案,因此请权衡选项,选择一个感觉正确的答案,然后实施并推送代码。