zoukankan      html  css  js  c++  java
  • 构建通用类型 继承 VS 聚合

     

    继承和聚合的比较GoF[1]做了详尽的阐述,在此偶将从实践的角度用一个例子来提供一种比较通用的解决方案,对继承和聚合做一个适用本案例的选择。此文乃一个案,并不代表两者的绝对优劣,具体问题还是要具体分析。

     

    【问题】

    CAD或画图软件设计设计中,会存在大量的基本体[2],如line circlearc polyline sphere box等。在组织它们之间的关系的时候,一般会有如下的继承体系:

    图表 1 基本体类结构

     

    即对每一种基本体,都有一个class与之对应。若有100种基本体,那就得有100classEntity继承而来。

    但从这些class本身来看,问题并没有多么严重,毕竟不同的基本体总得有个classobject异或别的什么东西与之对应。一个完整的画图软件总得有序列化机制、总得有个undo/redo机制、总得有个界面显示这些纷纷乱乱的基本体的参数以供交互式操作吧。因此,每个类又得加入save/load操作,undo/redo支持,再加上套UI class[3]。记得N年前做的一个CAX项目中,但为基本体写UI class就花了2W行代码,现在想想有些汗颜。

     

    图表 2 属性类与基本体类关系

    图表 3 CAD示例

     

    在写了N多相似的类后未免让人厌倦,让人有种重构的冲动。实现界面与数据分离可以使用脚本的办法,在此不作赘述

     

    【解决方案】

    对于一个绘图程序,其基本体主要有两部分内容:参数 + 构建方法。各种基本体之间的差异也存在于此。数据部分可以用一个variant[4]容器统一来描述,通过一个参数ID提取不同的参数。差异最大在于创建实体的方法,即作用于参数的行为。再次抽象后,通用基本体类型层次关系如下:

    图表 4 通用基本体类型类结构

     

    各种基本体类型都用Primitive统一描述,不再从它继承子类,而是实现不同的创建基本体的BuildMethod。最后用一个Factory模式管理各种BuildMethod,根据与Primitive绑定的BuildMethod ID,创建几何形状。

     

    由此所带来的好处是:

    1.       Save/Load只需要在Primitive实现

    2.       Undo/Redo只需要在Primitive实现

    3.       可以从Primitive的参数类型描述中提出GUI表现形式[5]

    4.       可扩展性得到增强,新增的类型无需考虑以上三条。

     

    由此所带来最大的坏处就是性能上有所损失。从variant得到具体的数据类型毕竟没有直接用原始的数据类型来的高效些。从使用的效果来看,并不会产生用户交互上的延迟。

     

    【总结】

             前后两种方法的主要差别在于是使用继承还是聚合,以及是如何使用继承的。二者本身没有优劣之分,但在具体的情景下就需要权衡利弊。

            


    --- 力为

     

    [1] 《设计模式》

    [2] 指基本几何类型。不知道这世界上有多少基本体,在不同的领域中可能基本体的定义也不尽相同。建筑中,可能门,窗都算作是基本体。

    [3] boost::serialization 提供了一种非侵入式的序列化方法,值得一试。

    Undo/redo的实现可以参考GoFMemento Pattern.

    [4] variant的实现有多种方法,boost有两种,参考boost::any boost::variant 的区别

    [5] 提取形式亦可参考如何从脚本提取UI的实现方法。

     
  • 相关阅读:
    2. Add Two Numbers
    1. Two Sum
    leetcode 213. 打家劫舍 II JAVA
    leetcode 48. 旋转图像 java
    leetcode 45. 跳跃游戏 II JAVA
    leetcode 42. 接雨水 JAVA
    40. 组合总和 II leetcode JAVA
    24. 两两交换链表中的节点 leetcode
    1002. 查找常用字符 leecode
    leetcode 23. 合并K个排序链表 JAVA
  • 原文地址:https://www.cnblogs.com/aiwz/p/6333140.html
Copyright © 2011-2022 走看看