I am stuck in a weird Design problem,
我陷入了一个奇怪的设计问题,
I am working on a two type of profiles Models,
我正在研究两种类型的profiles模型,
- User profile (belongs to User)
- 用户配置文件(属于用户)
- others that are maintain in-site as "bots" (doesn't belong to anybody)
- 其他以“bot”形式在站点中维护的机器人(不属于任何人)
The typical OO behaviour of these two types of Profiles is same but only the important attributes/properties are common ( the very important ones 5-6 in number), others properties like "interests etc"(almost 10-15 properties) are not there for bot profiles
这两种类型的概要文件的典型OO行为是相同的,但是只有重要的属性/属性是常见的(非常重要的5-6),其他属性如“兴趣等”(几乎10-15个属性)不存在于bot配置文件中。
The coder who worked on this earlier created separate models/Controllers for bot profiles / User profiles which creates a lot of redundancy everywhere and also as expected hard to maintain, write tests etc.I wanted to DRY this up, atleast to solve some/all of these redundancy problems.
之前做过这方面工作的程序员为bot概要文件/用户概要文件创建了单独的模型/控制器,这在所有地方都创建了大量冗余,并且如预期的那样难于维护,编写测试等。
Somebody suggested Single Table Inheritance as a solution
有人建议使用单表继承作为解决方案
Somebody suggested Use Polymorphic Associations instead.
有人建议用多态性联想来代替。
what is the better approach. When do we actually use STI?
什么是更好的方法。我们什么时候真正使用STI?
My own thought was STI is used best when attributes are same for Models and they differ in behaviour.
我自己的想法是,当模型的属性相同且行为不同时,STI是最好用的。
Thoughts about what can I do?
我能做什么?
4 个解决方案
#1
35
Characterising STI as mostly useful when attributes are the same but behaviour differs is "about right", but possibly a little limiting. I like to use STI when there is, as the name suggests, a clear OO-style inheritance relationship, rather than the database-style relationship between objects of different types.
在属性相同但行为不同的情况下,STI的特点是“正确”,但可能有一些限制。正如其名称所示,我喜欢在具有清晰的oo样式继承关系时使用STI,而不是不同类型对象之间的数据库样式关系。
If there is common code between bots and users, I'd say STI sounds like a winner. If there's just some common attributes, it's probably less applicable but still worth having a go at.
如果在机器人和用户之间有共同的代码,我想STI听起来像个赢家。如果只有一些公共属性,它可能不太适用,但仍然值得一试。
I'm a pretty experimental person, so my recommendation is to give it a go. Branch your code and refactor the models into an STI relationship. See if it really does dry things up, or just swaps one set of headaches for some other problem.
我是一个很有实验精神的人,所以我的建议是尝试一下。将代码分支并重构到STI关系中。看看它是否真的干了什么,或者只是用一套头痛的东西来替代其他的问题。
One thing I think you won't see much benefit from is drying up your controllers. In my experience, STI models don't often translate into similarly related controllers. But that would be something else to experiment with. Sometimes there's a win, sometimes there isn't.
有一件事我认为你不会从中受益,那就是让你的控制器变干。根据我的经验,STI模型通常不会转化为类似的相关控制器。但那将是另一种实验。有时有胜利,有时没有胜利。
#2
29
I've written an article on this very topic, including some tips for working with STI:
我已经写了一篇关于这个话题的文章,包括一些与STI合作的建议:
Single Table Inheritance in Rails
Rails中的单表继承
In short: there needs to be a clear OO-style inheritance relationship among objects (as eloquently stated by womble), not just some shared data. If there isn't a natural and obvious class hierarchy, a STI design may become difficult to maintain as your application evolves.
简而言之:对象之间需要有一个清晰的oo风格的继承关系(正如womble雄辩地指出的那样),而不仅仅是一些共享数据。如果没有一个自然而明显的类层次结构,那么随着应用程序的发展,STI设计可能会变得难以维护。
Secondly, you should consider if it's important to have all the data in one table. With polymorphic associations, your database queries will become more complex, and probably slower. If you're planning on listing all the objects together on the site (eg, in a table) then STI may be the way to go.
其次,您应该考虑将所有数据放在一个表中是否重要。使用多态关联,您的数据库查询将变得更复杂,而且可能更慢。如果你打算把所有的对象都列在网站上(例如,在表格中),那么STI可能是你的出路。
Thirdly, make sure your child classes don't have too many unique attributes. With all the data in one table, you don't want a lot of non-global columns. Not only do these take up space (not a major concern), but they make the data structure confusing. If you do have "special" columns you should explain them explicitly in your code.
第三,确保您的子类没有太多的惟一属性。有了一个表中的所有数据,就不需要很多非全局列。这些不仅占用了空间(不是主要问题),而且使数据结构变得混乱。如果您确实有“特殊”列,您应该在代码中显式地解释它们。
Lastly, if you do use STI, I strongly recommend using a single controller for all of your child models. The main function of a controller is to provide access to objects, and if the objects need to be accessed in very different ways, then STI may not have been the correct design choice to begin with.
最后,如果您确实使用STI,我强烈建议对所有子模型使用单个控制器。控制器的主要功能是提供对对象的访问,如果需要以非常不同的方式访问对象,那么STI可能不是正确的设计选择。
Check out my article (link above) for some more useful tips.
查看我的文章(上面的链接)一些更有用的技巧。
#3
5
I would probably use either STI or no special features at all. You might be able to call everything a Profile and you'd know if it was a "bot" if its user was nil. You could also store a "type" field without using STI.
我可能会使用STI或者没有特别的功能。你可以把所有的东西都称为概要文件,如果它的用户是nil,你就知道它是否是一个“机器人”。您也可以不使用STI来存储“type”字段。
Certain things would affect my decision to use STI:
某些事情会影响我使用STI的决定:
- Whether there is bot-specific logic
- 是否存在特定于机器人的逻辑
- How many bots there are versus users profiles (small number of bots means STI is OK - lots of bots and I might store them somewhere else)
- 有多少机器人和用户的配置文件(少量的机器人意味着STI是可以的-很多机器人,我可以把它们储存在其他地方)
The reason to avoid STI is sometimes it can get in your way. For instance it can be fairly annoying to change an object from one type to another (a Bot to a Profile in this case). Sometimes a simple "type" field is better.
避免性传播感染的原因是它有时会阻碍你。例如,将对象从一种类型更改为另一种类型(在这种情况下,将一个Bot更改为一个概要文件)可能相当烦人。有时简单的“类型”字段更好。
Its worth noting that you'll probably want a common base class if you use STI. So you may want Profile
, BotProfile
, and UserProfile
. The names are up to you. :)
值得注意的是,如果使用STI,您可能需要一个公共基类。你可能需要配置文件,僵尸文件,和用户文件。名字由你决定。:)
#4
4
One gotcha of Rails STI - most plugins (and so forth) don't support it fully. You will find yourself patching many of the common ones.
Rails STI—大多数插件(等等)都不完全支持它。你会发现自己修补了许多常见的问题。
#1
35
Characterising STI as mostly useful when attributes are the same but behaviour differs is "about right", but possibly a little limiting. I like to use STI when there is, as the name suggests, a clear OO-style inheritance relationship, rather than the database-style relationship between objects of different types.
在属性相同但行为不同的情况下,STI的特点是“正确”,但可能有一些限制。正如其名称所示,我喜欢在具有清晰的oo样式继承关系时使用STI,而不是不同类型对象之间的数据库样式关系。
If there is common code between bots and users, I'd say STI sounds like a winner. If there's just some common attributes, it's probably less applicable but still worth having a go at.
如果在机器人和用户之间有共同的代码,我想STI听起来像个赢家。如果只有一些公共属性,它可能不太适用,但仍然值得一试。
I'm a pretty experimental person, so my recommendation is to give it a go. Branch your code and refactor the models into an STI relationship. See if it really does dry things up, or just swaps one set of headaches for some other problem.
我是一个很有实验精神的人,所以我的建议是尝试一下。将代码分支并重构到STI关系中。看看它是否真的干了什么,或者只是用一套头痛的东西来替代其他的问题。
One thing I think you won't see much benefit from is drying up your controllers. In my experience, STI models don't often translate into similarly related controllers. But that would be something else to experiment with. Sometimes there's a win, sometimes there isn't.
有一件事我认为你不会从中受益,那就是让你的控制器变干。根据我的经验,STI模型通常不会转化为类似的相关控制器。但那将是另一种实验。有时有胜利,有时没有胜利。
#2
29
I've written an article on this very topic, including some tips for working with STI:
我已经写了一篇关于这个话题的文章,包括一些与STI合作的建议:
Single Table Inheritance in Rails
Rails中的单表继承
In short: there needs to be a clear OO-style inheritance relationship among objects (as eloquently stated by womble), not just some shared data. If there isn't a natural and obvious class hierarchy, a STI design may become difficult to maintain as your application evolves.
简而言之:对象之间需要有一个清晰的oo风格的继承关系(正如womble雄辩地指出的那样),而不仅仅是一些共享数据。如果没有一个自然而明显的类层次结构,那么随着应用程序的发展,STI设计可能会变得难以维护。
Secondly, you should consider if it's important to have all the data in one table. With polymorphic associations, your database queries will become more complex, and probably slower. If you're planning on listing all the objects together on the site (eg, in a table) then STI may be the way to go.
其次,您应该考虑将所有数据放在一个表中是否重要。使用多态关联,您的数据库查询将变得更复杂,而且可能更慢。如果你打算把所有的对象都列在网站上(例如,在表格中),那么STI可能是你的出路。
Thirdly, make sure your child classes don't have too many unique attributes. With all the data in one table, you don't want a lot of non-global columns. Not only do these take up space (not a major concern), but they make the data structure confusing. If you do have "special" columns you should explain them explicitly in your code.
第三,确保您的子类没有太多的惟一属性。有了一个表中的所有数据,就不需要很多非全局列。这些不仅占用了空间(不是主要问题),而且使数据结构变得混乱。如果您确实有“特殊”列,您应该在代码中显式地解释它们。
Lastly, if you do use STI, I strongly recommend using a single controller for all of your child models. The main function of a controller is to provide access to objects, and if the objects need to be accessed in very different ways, then STI may not have been the correct design choice to begin with.
最后,如果您确实使用STI,我强烈建议对所有子模型使用单个控制器。控制器的主要功能是提供对对象的访问,如果需要以非常不同的方式访问对象,那么STI可能不是正确的设计选择。
Check out my article (link above) for some more useful tips.
查看我的文章(上面的链接)一些更有用的技巧。
#3
5
I would probably use either STI or no special features at all. You might be able to call everything a Profile and you'd know if it was a "bot" if its user was nil. You could also store a "type" field without using STI.
我可能会使用STI或者没有特别的功能。你可以把所有的东西都称为概要文件,如果它的用户是nil,你就知道它是否是一个“机器人”。您也可以不使用STI来存储“type”字段。
Certain things would affect my decision to use STI:
某些事情会影响我使用STI的决定:
- Whether there is bot-specific logic
- 是否存在特定于机器人的逻辑
- How many bots there are versus users profiles (small number of bots means STI is OK - lots of bots and I might store them somewhere else)
- 有多少机器人和用户的配置文件(少量的机器人意味着STI是可以的-很多机器人,我可以把它们储存在其他地方)
The reason to avoid STI is sometimes it can get in your way. For instance it can be fairly annoying to change an object from one type to another (a Bot to a Profile in this case). Sometimes a simple "type" field is better.
避免性传播感染的原因是它有时会阻碍你。例如,将对象从一种类型更改为另一种类型(在这种情况下,将一个Bot更改为一个概要文件)可能相当烦人。有时简单的“类型”字段更好。
Its worth noting that you'll probably want a common base class if you use STI. So you may want Profile
, BotProfile
, and UserProfile
. The names are up to you. :)
值得注意的是,如果使用STI,您可能需要一个公共基类。你可能需要配置文件,僵尸文件,和用户文件。名字由你决定。:)
#4
4
One gotcha of Rails STI - most plugins (and so forth) don't support it fully. You will find yourself patching many of the common ones.
Rails STI—大多数插件(等等)都不完全支持它。你会发现自己修补了许多常见的问题。