使用继承来封装组合

时间:2016-10-11 13:21:38

标签: .net inheritance composition solid-principles

这种良好/可接受的做法是从对象派生而来隐藏与之相关的所有逻辑 创造那个对象。

例如(尽管不是完美的例子)我有一个Scene类。我想用一些实体,一些系统,设置背景颜色等来初始化它。 我可以为此创建Factory,但我选择在派生类的构造函数中执行所有操作。

而不是:

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?

1 个答案:

答案 0 :(得分:1)

你已经确定了每个组合子类方法的确切问题:它必然会编译时间,使得运行时组合变得更加困难。

此外,将组合逻辑硬编码到子类构造函数中需要您每次需要更改逻辑时重新编译,即使唯一改变的是系统内的运行时实例图。

您可以通过添加描述连接而不创建连接的类来解决在运行时编写对象的要求,然后添加一个构造函数来获取描述,并将它们处理为完整的Scene对象。

为了减少这种抽象,请考虑一种您喜欢的人类可读格式的配置文件,例如

{"Systems":["ColisionSystem", "MovementSystem"], "SceneGraph":"MyCustomSceneGraph"}

以及一个允许您访问此数据的界面:

interface SceneConfiguration {
    IList<String> Systems {get;}
    String SceneGraph {get;}
    ... // More configuration items
}

现在考虑一个从这个表示中生成SceneConfiguration实例的解析器,以及一个以Scene为参数的SceneConfiguration构造函数:

public Scene(SceneConfiguration config)

这种安排可以让你软件代码&#34;通过配置文件组成。该方法也适用于场景编辑器:场景编辑器创建SceneConfiguration的实例,而Scene仍然可以控制创建自己。