使用继承来封装组合
Using inheritance for encapsulating composition
这是good/acceptable从对象派生的做法只是为了隐藏所有与
创建该对象。
例如(虽然不是完美的例子)我有一个场景class。我想用一些实体、一些系统、设置背景颜色等来初始化它。
我可以为此创建工厂,但我选择在派生 class.
的构造函数中完成所有这些工作
而不是这个:
var scene = new Scene();
scene.Systems (new ColisionSystem);
scene.Systems (new MovementSystem);
scene.SceneGraph = new MyCustomSceneGraph();
我这样做:
class MyScene : Scene
{
void MyScene(SceneGraph sceneGraph)
{
this.Systems (new ColisionSystem);
this.Systems (new MovementSystem);
this.SceneGraph = sceneGraph;
}
}
var scene = new MyScene(new MyCustomSceneGraph());
所以我将所有创建的东西隐藏在构造函数中,作为奖励,我为我将创建的每个场景都获得了单独的文件。
在另一条路上。如果我曾经创建一个场景编辑器,这可能是个问题。因为在那种情况下,场景对象的客户端应该负责准备场景,而不是场景本身。
那么这是可以接受的做法还是违反了 SRP?
您已经确定了 subclass-per-composition 方法的确切问题:它必然会占用编译时间,使 运行-time 组合变得更加困难。
此外,将组合逻辑硬编码到 subclass 构造函数中需要您在每次需要更改逻辑时重新编译,即使唯一更改的是 运行 -系统内的时间实例图。
您可以通过添加描述连接而不创建连接的 class 来解决在 运行 时组合对象的要求,然后添加接受描述并处理它们的构造函数变成一个完整的 Scene
对象。
为了让这个不那么抽象,考虑一个您最喜欢的人类可读格式的配置文件,例如
{"Systems":["ColisionSystem", "MovementSystem"], "SceneGraph":"MyCustomSceneGraph"}
以及允许您访问此数据的界面:
interface SceneConfiguration {
IList<String> Systems {get;}
String SceneGraph {get;}
... // More configuration items
}
现在考虑一个从该表示中生成 SceneConfiguration
实例的解析器,以及一个将 SceneConfiguration
作为其参数的 Scene
的构造函数:
public Scene(SceneConfiguration config)
这种安排可以让你"soft-code"通过一个配置文件来组合。该方法也适用于场景编辑器:您的场景编辑器创建 SceneConfiguration
的实例,而 Scene
仍然控制创建自身。
这是good/acceptable从对象派生的做法只是为了隐藏所有与 创建该对象。
例如(虽然不是完美的例子)我有一个场景class。我想用一些实体、一些系统、设置背景颜色等来初始化它。 我可以为此创建工厂,但我选择在派生 class.
的构造函数中完成所有这些工作而不是这个:
var scene = new Scene();
scene.Systems (new ColisionSystem);
scene.Systems (new MovementSystem);
scene.SceneGraph = new MyCustomSceneGraph();
我这样做:
class MyScene : Scene
{
void MyScene(SceneGraph sceneGraph)
{
this.Systems (new ColisionSystem);
this.Systems (new MovementSystem);
this.SceneGraph = sceneGraph;
}
}
var scene = new MyScene(new MyCustomSceneGraph());
所以我将所有创建的东西隐藏在构造函数中,作为奖励,我为我将创建的每个场景都获得了单独的文件。
在另一条路上。如果我曾经创建一个场景编辑器,这可能是个问题。因为在那种情况下,场景对象的客户端应该负责准备场景,而不是场景本身。
那么这是可以接受的做法还是违反了 SRP?
您已经确定了 subclass-per-composition 方法的确切问题:它必然会占用编译时间,使 运行-time 组合变得更加困难。
此外,将组合逻辑硬编码到 subclass 构造函数中需要您在每次需要更改逻辑时重新编译,即使唯一更改的是 运行 -系统内的时间实例图。
您可以通过添加描述连接而不创建连接的 class 来解决在 运行 时组合对象的要求,然后添加接受描述并处理它们的构造函数变成一个完整的 Scene
对象。
为了让这个不那么抽象,考虑一个您最喜欢的人类可读格式的配置文件,例如
{"Systems":["ColisionSystem", "MovementSystem"], "SceneGraph":"MyCustomSceneGraph"}
以及允许您访问此数据的界面:
interface SceneConfiguration {
IList<String> Systems {get;}
String SceneGraph {get;}
... // More configuration items
}
现在考虑一个从该表示中生成 SceneConfiguration
实例的解析器,以及一个将 SceneConfiguration
作为其参数的 Scene
的构造函数:
public Scene(SceneConfiguration config)
这种安排可以让你"soft-code"通过一个配置文件来组合。该方法也适用于场景编辑器:您的场景编辑器创建 SceneConfiguration
的实例,而 Scene
仍然控制创建自身。