首页 > 解决方案 > 不包括成员函数和继承,向类添加功能的一些最常见的编程模式是什么?

问题描述

解决这个问题的方法可能不超过 2-4 种。

我有一种情况,我到处都在使用一个普通的类,并且(有时)我想赋予它特殊的能力。为了论证,假设类型检查不是必需的。

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

  1. 我见过的一种方式是“装饰器”模式,其中一种 mutator 环绕类,稍微修改它,并吐出一个具有更多功能的版本。

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

  3. ???

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

标签: classmember-functionsnon-member-functions

解决方案


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

正如您所提到的,对于简单的系统,标准方法是使用适配器模式:将“特殊能力”子类化,然后在需要时调用该特定子类。如果您需要添加的特殊能力的范围是已知的并且相当小,那么这绝对是最佳选择,即您通常只使用基类,但对于需要额外功能的三到五个地方。

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

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

    class MyClass{};
    DecoratedClass = decorate(MyClass);
    
  • 子类的组合 AbstractFactory/Adaptor 构建器(适用于子类中的功能分组可能在实现上有所不同的情况)

    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(); 
        }
    }
  • 策略模式也可以工作,具体取决于用例。但是,对于您不想更改的现有基类,这将是一个更重的提升,并且取决于它是否是在这些子类之间更改的策略。访问者模式也可以适用,但会遇到同样的问题,并且涉及对基类周围架构的重大更改。

    class MyClass{
      public sort() { Globals.getSortStrategy()() }
    };
    
  • 最后,如果所需的“特殊能力”足以(或最终足以)证明一个全新的界面是合理的,那么这可能是使用扩展对象模式的好时机。尽管它确实使您的客户或子类更加复杂,因为他们必须管理更多:检查特定的扩展对象及其所需的方法是否存在等。

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

说了这么多,保持它尽可能简单,有时您只需要编写特定的子类或一些适配器就可以了,尤其是在许多其他地方使用预先存在的类时。您还必须询问您希望课程开放多少以进一步扩展。使用抽象工厂降低技术债务可能是值得的,因此当您在未来添加更多功能时需要做的更改更少。或者,为了便于理解和简单,您真正想要的是锁定类以防止进一步扩展。您必须检查您的用例、未来计划和现有架构,以决定前进的道路。很有可能,有很多正确的答案,只有几个非常错误的答案,所以权衡选项,选择一个感觉对的,


推荐阅读