3

我不知道我应该多认真地继承..

在我的应用程序中,与大多数应用程序一样,我有客户、用户和供应商。

好吧,看起来很容易,但要成为细节的坚持者,我应该执行以下操作:

class Person {...}


class NaturalPerson extends Person {...}

class JuristicPerson extends Person {...}



class User extends NaturalPerson {...}

class Supplier extends JuristicPerson {...}

那么,客户呢?在我看来,他们也可能是自然人和法人……

class JurCustomer extends JuristicPerson {...}

class NatCustomer extends NaturalPerson {...}

这将是愚蠢的工作,因为如果我想拥有所有客户,我需要选择两个相应的表......

基本上我更喜欢每个类型的表模式......但根据上面的层次结构,我认为它可能会变得有点复杂。

好吧,这只是一个例子。在许多情况下,层次结构会复杂得多……

4

2 回答 2

1

这里要考虑的设计模式是:

  • ActiveRecord一个对象,它在数据库表或视图中包装一行,封装数据库访问,并在该数据上添加域逻辑。

这是经典的 Table-per-Type 方法。如果没有对象关系阻抗不匹配,则该模式适用,例如,当您的表与对象结构 1:1 匹配时。如果您有关系数据,则必须开始在 ActiveRecord 上添加 ORM 功能,这不是该模式的用途。所以当你有一个等等时使用juristic_customer_tablejuristic_person_table

许多应用程序中的现实情况是 OO 结构与 DB 结构不匹配,因为两者处理的结构问题本质上是不同的。此外,保持两者解耦使独立开发更加容易。因此,DataMapper 通常是更好的选择,尽管更复杂。

  • SingleTableInheritance将类的继承层次结构表示为单个表,其中包含各种类的所有字段的列。

引用 POEAA:此模式“将继承结构的所有类的所有字段映射到单个表中”。当你提取数据时,你通过一个映射器(它也处理 CRUD)运行记录集,它知道用什么数据实例化哪个类。为了方便使用,表中还可以保存对象的类名。这显然会将您的类的实现细节泄漏到数据库中。


IMO 两种方法都是蠕虫病毒。您的继承层次结构对我来说也不太合理。请记住,继承意味着Subtype 是关于职责的 Supertype。当您发现您的供应商根本不像 JuristicPerson 时,您的子类型很可能会很快违反 LSP 。问问自己,供应商是否需要公开法人的所有功能。如果没有,请考虑第三种方法:

根本不要使用继承,而是使用聚合。找到保存数据的基本类。然后制作封装该角色职责的小型角色对象,例如

$supplier = new Supplier(new Juristic(new Person(PersonGateway::findById(1))));

然后,您的供应商将拥有执行与供应商相关的事情的所有逻辑。在与供应商交互时,您可能不需要任何法律或个人的东西。这都应该是供应商内部的。通过这种方式,您的公共供应商接口将变得更小,并且更清晰地分离您的对象可以履行的职责。

这样你就不会创建 is-a 关系,而是 has-a 或 uses-a。我假设 Juristic 拥有某种与您的用例相关的业务逻辑。如果 Juristic 和 Natural 之间的唯一区别是语义,则将其完全删除。有关更多详细信息,请参阅我关于为真实世界建模的博客文章。

于 2013-06-19T07:07:48.197 回答
1

不必要的抽象层会增加复杂性,但不会带来任何好处。

您需要做的是确定可以从共享共同祖先的类中获得哪些实现好处。

我认为设计应用程序的最佳方式可能是从准确表示您正在处理的实体和关系的数据库模式开始。然后创建您的类以镜像该模式(每种类型的表)。

然后在考虑相似类的功能时,确定不同类型是否会从共享基类中受益。例如,基于这种设计技术,您最终会得到一个 Customer 和一个 Supplier 类。部分要求规定您需要一种获取信息以打印邮寄标签的方法。如果您获得此信息所经历的过程是相同的,那么设计一个抽象类是有意义的,然后两者都将扩展以实现该方法。

这将有助于在设计您的应用程序时管理复制粘贴编码。

于 2013-06-19T07:08:21.703 回答