在本文中,我将尝试讨论一种称为控制反转/ IoC的设计原则,也称为好莱坞原则。 我将展示这与
取代Barbara Liskovo(LSP)的
原理以及对私人与受保护的圣战
有何贡献。

作为序言,我想谈谈自己。 我是一名经过培训的软件工程师,已经在IT行业工作了10多年,最近我很喜欢写主题专业文章。 其中一些是成功的。 较早前,我在另一资源上发表了文章,不幸的是在俄罗斯无法访问(向Roskomnadzor致意)。 如果有人想了解他们,您就会知道该怎么做。
与往常一样,所有代码示例均在本文中以伪代码形式化为“讨厌的php”的形式提供。
初始任务
为了使它更快并且更易于理解,我们立即继续该示例。 我想从销售部门查看指标:我们每月,每天,每小时能赚多少钱。
我们在三个定期运行的团队的帮助下解决了这个问题:
- MonthlyReportCommand
- DailyReportCommand
- HourlyRerortCommand
我们将需要以下接口:
interface ReportCommandInterface { public function createReport(): Money; } interface MoneyRepositoryInterface { public function getMoney(Period $period): array; } interface MetricRepositoryInterface { public function saveMoneyMetric(Period $period, Money $amount, string $metricType); }
我们编写报告小组(省略了后者,因为对于那些想要理解和练习得很好的人来说,这是一个练习,自己编写):
class MonthlyReportCommand implements ReportCommandInterface {
我们看到在所有情况下,calculateTotals()方法的代码将完全相同。 首先想到的是将重复的代码放在一个通用的抽象类中。 像这样:

abstract class AbstractReportCommand { protected function calculateTotals(array $moneyRecords): Money {
computeTotals()方法是我们类内部机制的一部分。 我们谨慎关闭它,因为 外部客户不应调用它-我们不是为此设计的。 我们将此方法声明为受保护的,因为 我们计划在继承人中称呼他-这是我们的目标。 显然,这样的抽象类与类似库的类非常相似-它仅提供一些方法(对于php专家:也就是说,它的工作方式类似于Trait)。
抽象类的秘密
现在该休息一下示例,回顾一下抽象类的用途:
抽象类封装了通用机制,同时允许继承人实现自己的特定行为。抽象(lat。Abstractio-干扰)是对细节和概括的干扰。 目前,AbstractReportCommand类仅对所有报告进行通用计数。 但是我们可以通过使用好莱坞原理使我们的抽象更加有效,这听起来像是:
“不要给我们打电话,我们会给你自己打电话”为了了解它是如何工作的,让我们在AbstractReportCommand中加入一个通用的报告机制:

abstract class AbstractReportCommand implements ReportCommandInterface { private $moneyRepository; private $metricRepository;
我们做了什么? 抽象类的后代都不适用于通用机制(不要称呼我们)。 取而代之的是,抽象为其继承人提供了一种通用的功能方案,并要求它们仅使用结果来实现特定的行为功能(我们将挑战您)。
但是,承诺的IoC,LSP,私有与受保护的情况又如何呢?
那么控制反转与它有什么关系呢? 这个名字从哪里来? 很简单:首先,我们在最终实现中直接设置调用顺序,控制将执行的操作和时间。 后来,我们将此逻辑转换为通用抽象。 现在,抽象控制将调用什么以及何时调用,而实现则只需遵循这一点。 也就是说,我们反转了控件。
要解决此问题并避免
Barbara Liskov替换原理(LSP)出现问题 ,您可以通过在方法声明中包含final来关闭createReport()方法。 毕竟,每个人都知道LSP与继承直接相关。
abstract class AbstractReportCommand implements ReportCommandInterface { final public function createReport(): Money {
然后,AbstractReportCommand类的所有后代将严格地服从于无法重新定义的单个逻辑。 铁律,秩序,前程。
出于同样的原因,私有保护的优势也变得显而易见。 与通用功能机制相关的所有内容都应连接在抽象类中,并且不可重新定义-私有。 在特殊情况下需要重新定义/实现的所有内容均受抽象保护。 任何方法都是为特定目的而设计的。 而且,如果您不知道为方法设置什么样的范围,则意味着您不知道为什么要创建它。 此设计值得修改。
结论
构造抽象类总是最好使用控制反转,因为 使您可以充分利用抽象的思想。 但是在某些情况下使用抽象类作为库也是合理的。
如果您更广泛地看,那么好莱坞原则与抽象图书馆类之间的小镇对抗就变成了争论:框架(成人IoC)与图书馆。 证明其中哪个更好是没有意义的-每个都是为特定目的而创建的。 唯一重要的是有意识地创建此类结构。
感谢所有从头到尾认真阅读的人-您是我最喜欢的读者。