OOP原则 - 如何构建类

时间:2017-05-26 12:50:48

标签: php oop

我目前有一个类Message_Repository,其方法如下:

getLocationDetailsByID($messageId),
getCustomerDetailsById($messageId),
getMessages(),
updateMessageForEmail(array $data), //this takes an array which includes the message ID
getLinkIndicatorById($messageId),
setIndicator($data) //this takes an array which includes the message ID

这些方法都是数据库交互,在大多数情况下我选择的是各种数据,在某些情况下我正在进行更新。

我发现我正在充实,我的班级名称不再代表课堂上发生的事情,至少不是唯一的。

最佳做法是说一个Location_Repository类和一个Customer_Repository类,其中包含获取与主题相关的数据的方法吗?

仍在努力理解单一责任。理论上它看起来很简单,但在实践中我发现它更具挑战性,特别是当我的课程不断发展和变化时。绝对需要重构,但想确保我正确地考虑这个问题。

修改 我可能会对我班级的名字感到困惑。它不是严格意义上的设计模式的“存储库”,而只是我用来与数据库交互的类的命名约定。可能需要重命名它。

4 个答案:

答案 0 :(得分:2)

存储库应该只是管理实体或domain objects,它们是同一个类的实例。在您的特定情况下,您应该在Message实例,Location实例和Client实例中至少拆分三个单独的存储库。对于任何“链接指标”,可能还有第三个存储库。

此外,存储库类为not were your SQL code goes

对于SRP,代码遵循的最佳描述是:“当类只有一个改变的理由时”

如果你看一下福勒的文章,你会注意到,存储库实际上与它自己的多个依赖项进行交互。 SQL应该包含一个或多个data mappers

答案 1 :(得分:2)

Single responsability是雾化的OOP概念,导致Encapsulation concept

SOLID Principle这些概念受到compounded的约束,这是一个强大的原则,可以节省你的大部分时间,避免让你的余生头疼:

  

单一责任原则:一个班级应该只有一个   责任(即软件中只有一个潜在的变化)   规范应该能够影响类的规范)

     

开放/封闭原则“软件实体......应该是开放的   延期,但因修改而关闭。“

     

Liskov替换原则“程序中的对象应该是   可以替换它们的子类型实例而不改变它   该计划的正确性。“另见合同设计。

     

接口隔离原则“许多客户端特定的接口是   优于一个通用界面。“

     

依赖倒置原则应该“依赖于抽象,   [没有]结核。“

如果不了解您的所有业务规则并仔细阅读您的代码,就很难分析您应该如何整理软件,但我会给出一个镜头:

MessageRepository不会扩展客户或位置,但会由Composition Example扩展。

opposing Uncle Bob perspective 在上图中,来自维基百科的作品toke的一个例子

在MessageRepository的构造中,您将在MessageRepository中实例化这些要使用的类。完美的情况是避免在类中有公共变量,并且深深地依赖于方法来检索和设置数据(我看着你已经以这种方式做了一些事情)。所以,到目前为止,我可以通过方法名称理解:

MessageRepository方法:

  • public getMessages();
  • public updateMessageForEmail(array $ data); //这需要一个包含消息ID
  • 的数组
  • public getLinkIndicatorById($ messageId);
  • public setIndicator($ data); //这需要一个包含消息ID
  • 的数组

LocationRepository方法:

  • public getLocationDetailsByID($ messageId);

CustomerRepository方法:

  • public getCustomerDetailsById($ messageId);

记住这一点很重要:您的业务规则方法应该是私有的。

可读性建议:

  • 避免将下划线加入类名;
  • 避免重复班级名称或公共汽车。统治方法。 I.E. getLocationDetailsByID应该是getById(),永远记住 - 你的方法将有实例,因此将被称为:$ this-> location-> getById()。这同样适用于您描述的所有方法。

关于命名,这是一个很好的问题。我建议你学习设计模式/软件架构,我最喜欢的一个(Model-View-Controller)是MVC(MVC Schema)架构:

{{3}}

您的存储库'具有业务规则原则和数据库抽象的应该是一个模型,因此,如果你想使用该模式,创建MVC目录结构并努力实现它!

答案 2 :(得分:1)

通常我会将它们拆分,因此您可以为每种模型类型设置一个存储库。例如,返回“位置”模型的所有方法都应位于“位置”存储库中。与Update方法类似,将传递“位置”模型进行更新。

答案 3 :(得分:1)

如果我们将Doctrine存储库作为标准,那么几乎是的,您将拥有每种数据类型的存储库。

Message_Repository::getLocationDetailsByID();

可能会成为:

Location_Repository::getLocationDetailsByMessageID();

每个存储库都会获取单个职责,以获取与其自身数据类型相关的数据。

在Doctrine中,EntityRepository :: createQueryBuilder()通过->select(/* own data type */)预加载构建器有点隐含。

但是每个存储库都不同,您可以将数据类型分组为"概念"并且在坚持SRP的同时处理它们,但随着应用程序的增长,最好将它们分开。