开放/封闭原则 - 如何调用新版本


Open / Closed principle - How to call the new versions?

我试图掌握开放/封闭原则(就我而言,对于PHP,但这并没有真正的区别)。

我的理解是,一个类永远不会开放进行修改。仅用于修复错误。如果我想向类添加新代码,那么我必须创建一个新代码并扩展"旧"类。这是我向其添加新代码的唯一方法。

在某种程度上,我可以看到这样做的好处。因为基本上你创建了某种版本控制系统,旧代码总是可以工作的,但你也可以随时尝试使用新类。

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

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

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

$obj = new MyObject();

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

第一个问题。如何调用新类?因为它并不是一个完整的新对象。喜欢。用户对象是用户对象。我不能仅仅因为它需要另一种方法而突然给它起完全不同的名字。无论如何,我创建了新类:

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

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

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


所以基本上我的问题是:

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

如果"旧"类是从多个地方实例化(或继承)的,该怎么办?那我得把那些地方都找出来...收益在哪里?

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

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

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

我认为

通过添加函数,您不会修改类行为。

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

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

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

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

function __construct() {
    parent::__construct();
}

这样,您可以实例化新类并仍然访问扩展类的所有功能。

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

所以你可以做:

$newObj = new MyNewObject();
$newObj->doSomething();
$newObj->doSomethingElse();