何时创建一个类vs设置一个布尔标志?

时间:2010-12-15 21:38:09

标签: ruby-on-rails oop object

我有一个有趣的问题要提出;应该何时创建模型类/对象而不是为存储在数据库中的数据设置布尔标志?

例如,假设我有一个Person类,它具有President,Guard和PartTime的布尔标志。根据标志的值,对此类/模型的处理方式不同。因此,总统从Guard和PartTime(r)获得系统中的不同权限。

何时使用单表继承来表示此信息以及何时只会继续使用布尔标志?

我的直觉是使用STI将它们转换为不同的对象,因为这对我来说似乎更多。检查布尔值似乎在某种程度上是错误的,但我也可以看到它的位置。

更新澄清

让我使用另一个例子,因为上面的例子涉及太多案件。

我正在处理包含Pages的CMS应用程序,页面可以是公共页面,私有页面,共享页面,隐藏页面或默认页面(这意味着它是您在URL中未指定页面时获得的内容)。现在,我们有一个Page模型,一切都是一个布尔标志 - Public,Default,Shared。

我不相信这是处理此问题的最佳方法。特别是因为我们有规则来管理哪个页面可以是什么,即默认页面或共享页面必须是公共页面,而私有页面只是私有页面。

我同意下面的评论,人物角色的例子非常有意义。我不确定它的Page例子是什么。

为了使事情变得更复杂,只能有一个默认页面和一个共享页面。 STI可能允许我验证这一点,但我不确定,因为表中可能有许多默认和共享页面(只是与特定站点无关)。

注意:问题的上下文是Ruby on Rails应用程序,但适用于任何面向对象的语言。

4 个答案:

答案 0 :(得分:4)

首先,让我们确定通常使用的单表继承。这是一种将多个事物的存储和行为相互结合的方法。坚持使用CMS,一个示例是posts的表格,可以是CommentArticle。他们共享相似的数据和行为,但最终是不同的事情。无论某事是否是评论不是对象的状态,它都是一种身份。

但是,在您的示例中,无论页面是公共页面还是私有页面,是否共享或隐藏,都显示为页面的状态的一部分。虽然单表继承可能在技术上有效(假设所有子类都是互斥的),但它不适合。

状态应在一个或多个中实施。表示某个双重状态的属性可以指定为布尔值; 。如果页面总是为私有或公共,则可以将其建模为单个布尔列private。如果它不是私人的,那就是公开的(或者相反)。

在某些情况下,您可能希望存储三个或更多互斥的不同状态。例如,一个页面可以是私有,公共或共享(我不知道是否是这种情况 - 让我们假装它是)。在这种情况下,布尔值将无济于事。您可以使用多个布尔标志,但正如您正确观察到的那样令人困惑。最简单的方法是将其建模为enumeration。或者当您缺少此功能时(如Rails的情况),只需使用具有特殊含义的字符串值并添加验证,以确保您使用的唯一值是privatepublic或{{}之一1}}。

有时,不同状态变量的某些组合无效。例如,页面可能是草稿已批准(由布尔列shared反映);它也是 public private (也由布尔列反映)。我们可以决定在公开之前必须批准的页面。在这种情况下,我们声明其中一个状态无效。这应该通过模型的验证来体现。重要的是要意识到草案公共页面不是从根本上不可能,它只是不可能,因为你决定不应该发生。

在创建模型时,请仔细区分反映现实世界中主题的实际属性和状态的属性,以及确定内容的业务规则应该是可能的,不应该是什么。第一个应建模为列,第二个建模为验证。


原始答案:

一个明显的区别是布尔标志允许approved同时标记为总统。如果您的模型应该允许这些情况,单表继承将不适合您。

另一方面,总统Person行为可能与普通人不同;一个人只能成为总统后卫。在这种情况下,继承可能更合适。但我不认为你应该将“兼职”模型化为子类。无论如何,这是一个属性。

还有一个重要的第三个选项,即您可以将某个人的作业角色与模型完全分开。一个有一个(或多个?)工作,这些工作是兼职或不兼职。此模型的优点是您可以将人员的属性与其工作的属性分开。毕竟,人们会改变工作,但这并不能使他们成为一个与众不同的人。最终,在我看来,这是模拟你情况的最现实的方式。

答案 1 :(得分:0)

我不想为此使用标志,但也不要为此子类化Person。更确切地说,附加一个角色(或者如果你有一个既是总统又有卫士的角色,一组角色),并附有角色的子类来管理这些角色。

就个人而言,我既不是总统也不是卫兵,但我既是程序员又是音乐家,有时还担任过其他一些角色(事实上,我作为一名学生多年来同时兼任一名警卫前。)。

一个人有角色。

答案 2 :(得分:0)

我发现每当我想“嗯,我有这三种类型的行为并且它们看起来像子类,但需要在运行时更改”时,请查看策略或状态模式。它通常非常适合,并且通常也会在保持责任分开方面击败一个简单的布尔标志。

在您的情况下,此启发式方法会说您有一个具有AccessRights类型属性的Person,它决定是否可以执行某个操作。 Person可以访问此对象或委托适当的方法。之后,你有PresidentialRights,GuardRights和PartTimeRights实现这个AccessRights界面,你很高兴。

鉴于此,您无需在出现新类型的访问权限时更改人员类别,如果出现新类型的操作,您可能需要更改人员类别(取决于您是否委派以及如何委派)和为了添加新类型的AccessRights,您只需添加AccessRights的新实现。

答案 3 :(得分:0)

答案是它基本上是一个设计决定。没有一种先验正确的方法来设计架构。当您在它们之间定义类和关系时,您可以定义体系结构,同时还可以定义表示应用程序域的语言。

任何语言都由词汇组成(即人,总统,警卫等);语法(即您可以为词汇表实例指定的关系)和语义(即您在词汇和关系中指定的术语的含义)。

现在你可以以无限的方式获得相同的行为。任何人都会为同一个系统提出不同的架构,因为任何人都可能对问题有不同的思考方式。

尽管如此,在设计时还是应该考虑一些标准。 定义类时,您正在定义语言的“第一顺序”结构,当您为类定义属性时,您将描述第一个顺序结构的特征。

决定是否需要类或属性的最佳方法可能就是这个。 总统和警卫除了那些人之外还有不同的特点吗?如果是这种情况,并且它们具有许多不同的特征,那么你应该创建两个类(一个用于总统,一个用于Guard),这两个类都继承自Person。否则,您必须在Person类中折叠所有特征(属于人,属于总统和属于Guard的人),并将其有效性调整为另一个标志(类型)。这将是一个非常糟糕的设计

公开或不公开的页面的特征实际上描述了页面的状态。因此,将其建模为Page Class

的属性是非常合理的