2017-05-26 38 views
2

我现在有一类Message_Repository具有类似的方法:OOP原则 - 如何构建类

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类,该类将容纳获取与主题相关的数据的方法?

仍试图理解单一责任。理论上它似乎很简单,但实际上我发现它更具挑战性,特别是当我的课程不断发展和变化时。绝对需要重构,但要确保我正确地思考这个问题。

编辑 我可能会添加与我的班级的名称混淆。它不是严格意义上的设计模式的“存储库”,而仅仅是我用来与数据库进行交互的类的命名约定。可能需要重命名它。

+0

你能简单介绍一下这些功能的用途吗?你传递给这些功能的ID是什么?它是一个消息ID,还是位置/客户/ LinkIndicator ID? –

+0

@NiettheDarkAbsol消息ID是数据库中各个表之间的主键,大多数方法都使用该消息ID来获取所需的数据,所以它被传递到我提到的所有方法中。有一个或两个其他方法(我的问题中没有列出)不接收消息ID。 – hyphen

+0

我明白了。在这种情况下,你的构造函数应该使用这个ID,那么你应该把'getLocationDetails'作为对象的非静态方法,它会返回这些细节。 –

回答

2

Single responsability是OOP的原子化概念,它会导致Encapsulation concept

这些概念是由SOLID Principle粘合在一起的,强大的原理,将节省您大量的时间和避免麻烦你的余生:

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

打开/关闭原则“的软件实体......应该是开放的 扩展,但关闭modificati on“。

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

界面偏析原理“许多客户特定的接口是 多于一个的通用接口更好”。

依赖倒置原则一个应“取决于抽象, [不]结石。”

如果不理解您的所有业务规则并仔细阅读您的代码,则很难分析如何组织您的软件,但我会给出一个答案:

MessageRepository不会扩展客户或地点,但它们是compounded

Composition Example 在上图中,从维基百科

在你构建从MessageRepository你会实例这些类使用,你想里面MessageRepository组成托克的一个例子。完美的情况是避免在类中存在公共变量,并深深依赖方法来检索和设置数据(我看着你已经以这种方式做了一些事情)。

MessageRepository方法:那么,据我可以通过方法名称理解

  • 公众的getMessages();
  • public updateMessageForEmail(array $ data); //需要一个数组,其中包含消息ID
  • public getLinkIndicatorById($ messageId);
  • public setIndicator($ data); //这需要一个阵列,其包括消息ID

LocationRepository方法:

  • 公共getLocationDetailsByID($ MESSAGEID);

CustomerRepository方法:

  • 公共getCustomerDetailsById($ MESSAGEID);

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

建议可读性:

  • 避免强调到类名;
  • 避免重复类名或总线。统治方法。 I.E. getLocationDetailsByID应该是getById(),永远记住 - 你的方法将有实例,所以会被调用:$ this-> location-> getById()。这同样适用于你描述的所有方法。

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

MVC Schema

你的“库”,这有业务规则的原则和数据库抽象应该是一个模式,所以,如果你想使用该模式,创建MVC目录结构并努力实现它!

+0

关于可读性的要点。任何关于命名的想法?如果我有一个Location_Repository类,那应该是Location吗?我是否需要在名称中区分它作为访问数据库的东西,还是不必要?命名事情很难。 – hyphen

+0

我会提出我的回答,坚持 – calexandre

+0

恕我直言,UncleBob的讲座不太关于MVC,更多关于“Rails如何不做MVC”。 –

1

通常我会把它们分开,所以你将有一个每个模型类型的存储库。例如,所有返回“位置”模型的方法都应位于“位置”存储库中。与更新方法类似,它将传递一个'位置'模型来更新。

+0

他们不是“模型” –

1

如果我们使用Doctrine库去为标准,则非常肯定的,你就必须为每个数据类型的存储库。

Message_Repository::getLocationDetailsByID(); 

可能会变成:

Location_Repository::getLocationDetailsByMessageID(); 

单这里的责任是通过有关他们自己的数据类型每个仓库取数据遵守。在Doctrine中,EntityRepository :: createQueryBuilder()预加载了一个->select(/* own data type */)的构建器。

但每一个库是不同的,你可以组数据类型为“概念”和处理他们在同一个地方,同时还符合SRP,但随着应用的增长,最大努力把它分开。

2

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

此外,库类是not were your SQL code goes

对于SRP,代码遵守的最佳描述是:“当类只有一个原因需要更改时”

如果你看一下福勒的文章,你会发现,这是仓库实际上有它自己的多个依赖交互。并且SQL应该可能进入一个或多个data mappers

+0

这是关于库类的好信息。我认为对我来说,这仅仅是一个名字而不是一个具体的设计模式,因为我还没有经历过OOP。这本质上是一个数据访问类。任何模式或命名公约的建议呢? – hyphen

+1

版本库不是真正的“数据访问类”。我会说这是一种抽象,他们会在代码中放置代码,在选择哪个数据映射器用于与持久性进行交互时开始需要逻辑。那是你创建一个存储库来隔离这部分逻辑的时候。 Lemmes看看我能不能挖出一个代码的例子,在那里很有用。 –

+1

@hyphenas举个例子,[this method]中的大部分逻辑(https://github.com/glome/cbc/blob/overhaul/src/cashback/Model/Services/Recognition.php#L19)实际上应该被移动在一个存储库中(只是不要使用该代码库进行学习,这很糟糕),因为它可以让你将所有“摆弄”与“选择哪个映射器”相提并论。 –