使用封装打破大Class的设计方法
Design Method to Break Large Class Using Encapsulation
我有一个大数据 class (D
)(总共约 3000 行)。其用途可分为以下小节:
- I/O - Read/Write/Import/Create/Copy...(主要是解析二进制数据文件和建立数据结构——这部分本身就占代码的三分之一左右)
- 分析 - 大约 10 个函数来分析代码而不对其进行操作(每个函数彼此完全独立,但存在一些通用的辅助函数)
- Manipulation - 大约 10 个函数来操作数据集(与 Analysis 相同,除辅助函数外,方法之间没有交叉交互)
- Visualization - 可视化数据(这主要是将一个或多个数据集绘制到一个 matlab 图形中并使用 axes/cursor/zoom 句柄 - 但它需要将数据存储到图形中)
- 常用辅助函数 - 私有函数(如输入解析等)
我已经把可视化作为一个单独的 class (V
) 吐出来了。这主要是因为我可以将所有必要的可视化信息标记到 matlab figure
(使用 setappdata
),从而使可视化独立于 D
。为了直接调用 V
我在 D
.
中创建了一个包装器
我现在的问题是,这么大的class,我该如何进行拆分?我能想到的唯一三个选项是:
- 将方法转化为函数,全部放入文件夹
- 创建静态 classes 来模拟命名空间并以与要点相同的方式对方法进行排序。
- 留下怪物,看着它成长。
由于第一个和最后一个选项相当简单,我将举一个小例子说明第二个选项的含义:
我有一个主class:
classdef main < handle
properties (SetAccess = private)
analysis
end
methods
function obj = main
obj.analysis = analysis(obj);
...
end
...
end
end
和子classes
classdef analysis < handle
properties(SetAccess = private)
parent
end
methods
function obj = analysis(parent)
obj.parent = parent;
end
...
end
end
这会以某种方式对方法进行分组。
语言是 Matlab
重要的情况。
我拆分代码的解决方案是确保将内容分解为合理的组件。在这种情况下,我假设您要存储很多变量。这里的关键是功能化一切,并使用封装进行有意义的抽象。您可以 运行 通过此清单:
- 是否有某些函数是您始终使用一堆变量的?如果是这样,将它们分组到 class.
- 是否有某些 class 您在稍作修改后反复使用的东西?如果是这样,请使用 class 继承。
- 是否有某些 class 具有相似结构,但实现功能不同的东西?如果是这样,请使用抽象 classes.
- 不要忘记使用局部函数并尽可能尝试矢量化。
对于您的情况,在信息有限的情况下,我会将您的工作流程分开如下。
- I/O操作,应该大概应该抽象Read/Write/Import/Create/Copy到DataReader下的方法或更多classes(如果代码比你描述的更复杂)class
- 分析 - 如果每个功能相似,则创建 class 继承。否则,将其放入 DataAnalyzer class 并相应地使用本地函数。
- Manipulation - 根据这些操作的优先级,为每个级别的操作创建不同级别的 类。可能在 DataManipulator class 下完成所有操作,并使用 getter 进行计算。
- Visualization - 类似于 Manipulation,也为每种类型的可视化封装到 classes 中。您可能可以将其全部封装在 DataVisualizer class 下,并为您正在绘制的每个图形设置一个 plot/print 函数。
- 关于Local/Private函数,尝试为简单的计算创建匿名函数,如果更复杂则为局部函数。如果您发现在多个地方使用本地函数,您可能需要重新设计 class,在某处输入函数句柄,或在子文件夹中使用私有函数。
也许如果你概述你正在做什么以及你想做的更详细的行动,我可以提供进一步的帮助。
编辑: 添加了一些代码来举例说明:
我假设您的数据在操作过程中没有被覆盖。如果是,只需将其存储在同一个变量中。如果 algo1 与 algo2 相同,那么您可以在 functions/classes 之间进行一些互连以进一步减少代码。您可以通过使用继承或从 algo1() 调用 algo2() 来互连。
script.m
D = DataReader.readData( 'file.txt' );
A = DataAnalyzer.analyzeData( D );
M = DataManipulator.manipData( D );
DataVisualizer.plotGraphs( M );
DataAnalyzer.m
classdef DataAnalyzer
properties (SetAccess = private)
...
end
methods
function obj = DataAnalyzer( D )
...
end
function A = analyzeData( obj.D )
A.algo1 = obj.algo1(D);
A.algo2 = obj.algo2(D);
...
end
function a = algo1( obj, D );
...(algo here)
end
...
end
end
我有一个大数据 class (D
)(总共约 3000 行)。其用途可分为以下小节:
- I/O - Read/Write/Import/Create/Copy...(主要是解析二进制数据文件和建立数据结构——这部分本身就占代码的三分之一左右)
- 分析 - 大约 10 个函数来分析代码而不对其进行操作(每个函数彼此完全独立,但存在一些通用的辅助函数)
- Manipulation - 大约 10 个函数来操作数据集(与 Analysis 相同,除辅助函数外,方法之间没有交叉交互)
- Visualization - 可视化数据(这主要是将一个或多个数据集绘制到一个 matlab 图形中并使用 axes/cursor/zoom 句柄 - 但它需要将数据存储到图形中)
- 常用辅助函数 - 私有函数(如输入解析等)
我已经把可视化作为一个单独的 class (V
) 吐出来了。这主要是因为我可以将所有必要的可视化信息标记到 matlab figure
(使用 setappdata
),从而使可视化独立于 D
。为了直接调用 V
我在 D
.
我现在的问题是,这么大的class,我该如何进行拆分?我能想到的唯一三个选项是:
- 将方法转化为函数,全部放入文件夹
- 创建静态 classes 来模拟命名空间并以与要点相同的方式对方法进行排序。
- 留下怪物,看着它成长。
由于第一个和最后一个选项相当简单,我将举一个小例子说明第二个选项的含义:
我有一个主class:
classdef main < handle
properties (SetAccess = private)
analysis
end
methods
function obj = main
obj.analysis = analysis(obj);
...
end
...
end
end
和子classes
classdef analysis < handle
properties(SetAccess = private)
parent
end
methods
function obj = analysis(parent)
obj.parent = parent;
end
...
end
end
这会以某种方式对方法进行分组。
语言是 Matlab
重要的情况。
我拆分代码的解决方案是确保将内容分解为合理的组件。在这种情况下,我假设您要存储很多变量。这里的关键是功能化一切,并使用封装进行有意义的抽象。您可以 运行 通过此清单:
- 是否有某些函数是您始终使用一堆变量的?如果是这样,将它们分组到 class.
- 是否有某些 class 您在稍作修改后反复使用的东西?如果是这样,请使用 class 继承。
- 是否有某些 class 具有相似结构,但实现功能不同的东西?如果是这样,请使用抽象 classes.
- 不要忘记使用局部函数并尽可能尝试矢量化。
对于您的情况,在信息有限的情况下,我会将您的工作流程分开如下。
- I/O操作,应该大概应该抽象Read/Write/Import/Create/Copy到DataReader下的方法或更多classes(如果代码比你描述的更复杂)class
- 分析 - 如果每个功能相似,则创建 class 继承。否则,将其放入 DataAnalyzer class 并相应地使用本地函数。
- Manipulation - 根据这些操作的优先级,为每个级别的操作创建不同级别的 类。可能在 DataManipulator class 下完成所有操作,并使用 getter 进行计算。
- Visualization - 类似于 Manipulation,也为每种类型的可视化封装到 classes 中。您可能可以将其全部封装在 DataVisualizer class 下,并为您正在绘制的每个图形设置一个 plot/print 函数。
- 关于Local/Private函数,尝试为简单的计算创建匿名函数,如果更复杂则为局部函数。如果您发现在多个地方使用本地函数,您可能需要重新设计 class,在某处输入函数句柄,或在子文件夹中使用私有函数。
也许如果你概述你正在做什么以及你想做的更详细的行动,我可以提供进一步的帮助。
编辑: 添加了一些代码来举例说明:
我假设您的数据在操作过程中没有被覆盖。如果是,只需将其存储在同一个变量中。如果 algo1 与 algo2 相同,那么您可以在 functions/classes 之间进行一些互连以进一步减少代码。您可以通过使用继承或从 algo1() 调用 algo2() 来互连。
script.m
D = DataReader.readData( 'file.txt' );
A = DataAnalyzer.analyzeData( D );
M = DataManipulator.manipData( D );
DataVisualizer.plotGraphs( M );
DataAnalyzer.m
classdef DataAnalyzer
properties (SetAccess = private)
...
end
methods
function obj = DataAnalyzer( D )
...
end
function A = analyzeData( obj.D )
A.algo1 = obj.algo1(D);
A.algo2 = obj.algo2(D);
...
end
function a = algo1( obj, D );
...(algo here)
end
...
end
end