C++:类功能子集的推荐设计模式?

Posted

技术标签:

【中文标题】C++:类功能子集的推荐设计模式?【英文标题】:C++: recommended design pattern for subsets of class functionality? 【发布时间】:2013-12-11 06:05:34 【问题描述】:

我正在就一种非常适合我的需求的设计模式寻求建议:

在我的 C++ 项目中,一个特定的纯虚拟类将代表某个概念的所有相关功能的超集,而从该纯虚拟类派生的具体类将是该超集的某个不同的有限子集。这些具体类中只有一个实例在运行时存在。

如果我使用 C 编程,我可能会选择将其实现为函数指针的结构,并为任何缺失的功能使用 NULL。但这对 C++ 来说并不是很令人满意。

关于我能想到的唯一想法是一个类,其中每个成员函数都是“受保护的”,以及一组匹配的“公共”成员函数指针。构造函数将负责将 MFP 初始化为 NULL 或相应成员函数的地址,具体取决于该类提供的功能。

但这实际上只比我上面第一次提到的 C-struct-of-function-pointers 稍微多一点 C++ 风格。而且,也许它已经足够好了。但我想知道是否有人可以针对这种情况提出一种更令人满意、更有见地的设计模式。

我对任何普遍接受的做法持开放态度。 STL 没问题。

更新:MFP 方法不是很令人满意的原因是,我必须为那些不适用的存根实现无操作存根——因为纯虚拟基类——即使我将它们各自的 MFP 设置为 NULL。 进一步思考,这个更新完全是假的。 (它们不会是无所事事的存根,它们将是有用的功能,在 MFP 不使用 NULL 的情况下。我想我累了。)

更新 2:打个比方:我的项目支持可以换出的硬件模块。它们基本上都是同一类功能,但在特性和功能上有所不同。在启动时,我必须检测实际连接的硬件模块,并实例化适当的类。但是我不希望使用该类的代码对每个类都有特殊的了解;我希望班级宣传它提供的功能。 (有时,两个硬件模块将标识为相同的类型 ID,但在功能探测中,一个会指示另一个不具有的功能。)

【问题讨论】:

(我不确定这个问题是否适合 S.O.,但我不知道还能问哪里。) 这个设计很可能一开始就走错了路。但是在某些情况下,这样的事情是合适的。一种解决方案是将功能分解为纯接口,每个具体类都可以随意继承和实现。然后客户端代码可以使用例如dynamic_cast 在运行时发现有什么功能。或者在模板代码中它可以使用std::is_base_derived(我记得它的参数顺序错误,但无论如何)。但是请考虑一下这种复杂性——它就是这样——是否有有用的目的。是吗? 我用一个类比更新了我的问题,举例说明了我觉得我需要这种方法的原因。特别是这部分:“有时,两个硬件模块将标识为相同的类型 ID,但在能力探测时,一个会指示另一个不具有的功能。” 对我来说,“函数指针结构”听起来很像 C++。 听起来像工厂创建设计模式之一可能在这里有用。 【参考方案1】:

您的设计要求违反了一个非常重要的 OOP principle。 如果一个类或一个函数依赖于那个“超集”接口,那么编译器将永远无法强制执行类型安全——你实际上是在与它作斗争,为了什么?

我建议您segregate 您的接口,并创建一个具体的(可能是纯虚拟的)类来实现所有这些。这种设计模式有一个名字——它叫做facade。

更新我现在阅读您的更新,我相信您需要一个工具来推广对象。 有两种促销方式:

实施促销: 这是您实质上替换对象实现的地方。这可以通过state 模式来完成,或者通过将您的对象放置新到具有不同VTABLE 的对象来完成。 功能提升: 这是您添加功能的地方,就像在更多功能中一样。您可以通过从硬件模块的名称到它的变体指针的映射来做到这一点。当您将一个对象提升到不同的类时,您只需替换指针变体。例如,如果您的第一个映射来自“COM1”-> GenericSerial*,那么您现在设置“COM1”-> SpecializedSerial*。您可以使用变体库,例如 boost's。

【讨论】:

【参考方案2】:

为什么不这样做:

interface All 
    void f1();
    void f2();
    void f3();

abstract class AllABC implements All 
    public void f1() 
        throw new RuntimeException("not implemented");
    
    public void f2() 
        throw new RuntimeException("not implemented");
    
    public void f3() 
        throw new RuntimeException("not implemented");
    

class F12 extends AllABC 
    public void f1() 
        System.out.println("f1");
    
    public void f2() 
        System.out.println("f2");
    

class F13 extends AllABC 
    public void f1() 
        System.out.println("f1");
    
    public void f3() 
        System.out.println("f3");
    

public class So20511733 
    public static void main(String[] arguments) 
        All f12=new F12();
        f12.f1();
        f12.f2();
        All f13=new F13();
        f13.f1();
        f13.f3();
    

【讨论】:

这是合理的,并且基本上是我(2 个月前)采用的方法,尽管接受了 Yam 的回答。最初我想要一个解决方案,其中客户端代码在尝试之前查询某些特定支持,但最终只是在不受支持时解决异常。

以上是关于C++:类功能子集的推荐设计模式?的主要内容,如果未能解决你的问题,请参考以下文章

C++进阶特殊类设计

C++进阶特殊类设计

C++进阶特殊类设计

自动化测试之-测试用例设计方法总结

最简单的设计模式——单例模式的演进和推荐写法(Java 版)

2 个具有相同功能但变量名不同的 C++ 类 - 使用哪种模式?