打开/关闭原则 - 如何调用新版本?

时间:2012-05-23 20:12:23

标签: php oop open-closed-principle

我正在尝试掌握开放/封闭原则(在我的情况下是PHP,但这并没有真正有所作为。)

我理解的方法是,一个班级从不打开进行修改。仅用于修复错误。如果我想在课程中添加新代码,那么我必须创建一个新代码并扩展“旧”类。这是我可以添加新代码的唯一方法。

在某种程度上我可以看到它的优点。因为基本上你创建了某种版本控制系统,旧代码总是可以工作,但你总是可以尝试使用新类。

但这在实践中如何运作?我的意思是,假设我有以下课程:

class MyObject
{
    public function doSomething()
    {
        echo 'Im doing something';
    }
}

所以某个地方我可能正在实例化这个类:

$obj = new MyObject();

但后来我决定在该对象中使用另一种方法是件好事。所以我也可以做其他事情。根据OCP,我无法修改课程。所以我必须创建一个新的,直到旧的一个?

第一个问题。我怎么称呼新课程?因为它实际上不是一个完整的新对象。喜欢。 User对象是User对象。我不能突然给它完全不同的名称,因为它需要另一种方法。无论如何,我创建了新类:

class MyNewObject extends MyObject
{
    public function doSomethingElse()
    {
        echo 'Im doing something else now';
    }
}

现在这也意味着我必须更改我实例化“MyObject”类的代码行,并将其替换为“MyNewObject”类,对吧..?如果在不止一个地方完成,那么我必须搜索我的源代码...(想想控制器类中的一个方法,它几乎总是使用'​​new'关键字来实例化某些类。)

同样基本上适用于继承。我必须找到继承旧类的每个类,并且必须用新类替换它。


基本上我的问题是:

如何命名具有新方法的新类?只是因为我添加了一些新功能,并不意味着我可以给全班一个全新的名字......

如果'old'类从多个地方实例化(或继承),该怎么办?然后我必须找到所有这些地方......收益在哪里?

3 个答案:

答案 0 :(得分:3)

我认为通过添加一个函数,你不会修改类行为。

在你的应用程序中当前正在调用doSomething()的所有实例中,只需将doSomethingElse()添加到类中就不起作用了。由于您没有更改doSomething(),因此行为与以前相同。

一旦确定doSomething()实现在某些情况下没有削减它,就可以扩展类并覆盖doSometing()。同样,原始版本的行为仍然与以往一样,但现在您还可以使用新的doSomething()。

我意识到这与开放/封闭的严格定义背道而驰,但这是现实世界,这就是我在代码中解释这一原则的方式。

答案 1 :(得分:3)

开放封闭原则并不打算用作一种版本控制系统。如果您确实需要对课程进行更改,请继续进行更改。您不需要创建新类并更改实例化旧类的所有位置。

开放封闭原则的要点是,精心设计的系统不应要求您更改现有功能以添加新功能。如果要向系统添加新类,则不需要搜索所有代码以查找需要引用该类的位置或具有特殊情况。

如果您的类的设计不够灵活,无法处理某些新功能,那么请务必更改类中的代码。但是当您更改代码时,请使其灵活,以便将来可以处理类似的更改而无需更改代码。这是一个设计政策,而不是一套手铐,以防止你做出改变。通过良好的设计决策,随着时间的推移,当您向系统添加新功能时,现有代码将需要越来越少的更改。这是一个迭代过程。

答案 2 :(得分:0)

您需要在MyNewObject类中创建一个构造函数,该构造函数调用父类的构造函数:

function __construct() {

    parent::__construct();

}

通过这种方式,您可以实例化新类,并仍然可以访问扩展类的所有功能。

然后你也可以覆盖父类中的任何函数(只要它当然没有标记为final)。

所以你可以这样做:

$newObj = new MyNewObject();

$newObj->doSomething();

$newObj->doSomethingElse();