为了明确我的意思,让我们建立一个假设的场景,可能需要这样做。
让我们说我正在为一家管理苏格兰威士忌啤酒厂的公司建造一些软件。每家啤酒厂公司都可以拥有该软件的副本来管理所有的商业物流。
假设我有一个Kettle
个对象,在其上我们会有一些属性,例如.Colour
和.Material
。
但是,如果Glenfiddich啤酒厂需要该域名上的其他财产呢?例如.Size
和其他一些啤酒厂并不关心以上所有内容,只对.Content
和.DateFermentationStarted
感兴趣?
在OOP中,有一种方法可以使我的Kettle
对象动态化(具有不同的属性和方法),具体取决于名为Customer
的参数吗?
如果我没有弄错的话,这与Polymorphsim非常不同。
答案 0 :(得分:3)
在这种情况下,您无法应用太多DDD,因为域概念定义会从一个客户端更改为另一个客户端。我的意思是我们都有一个水壶,但客户想要的任何财产都可以。你怎么能应用行为?更准确地说是什么?
最多您的"域名"对象将是数据结构。在定义对象以及定制选项是什么时,谁在说出来是很重要的。例如,如果客户可以从预定义的属性中进行选择,那么您就有一定的操作空间。
但是如果他们可以添加任何具有任何名称的属性,那么您将失去语义并最终得到由魔术字符串组成的数据结构。除非您还拥有客户可用于定义规则的业务规则编辑器,否则您无法执行业务规则。对于开发人员和客户来说,这将非常复杂。
所以,IMO,DDD并不适合这个,除非你为每个客户建立单独的应用程序,但仍然适当的OOP。您将使用数据结构,而ORM可能会对此有所帮助。
答案 1 :(得分:1)
如果这些属性是动态的,您有几种选择。
使基类具有公共属性,然后派生具有已定义新属性的新类。 但是,此解决方案存在一个问题 - 您必须为需要特殊属性的每个客户创建不同的构建。 优点是系统在代码级别的显式属性方面完全记录。
将属性建模为单独的自治类,并能够创建属性实例并在运行时将它们分配给域对象。 可以在DB(具有其名称,可能是数据类型)中定义属性,并将其分配给需要的某些域类。这样就不需要为每个不同的配置创建新的版本,只需要更新数据库。
这个简单的类图显示了这个想法:
其他属性在DB中定义,而不是在运行时读取并分配给域对象。
答案 2 :(得分:0)
首先感谢你让我对你的英国人的例子大笑:-D
我会做什么,并记住我是一个初学者,是拥有一个处理所有属性的域对象,以及一个派生类型,它还提供一个接口来告诉租户允许哪些属性进行读取。
interface iKettle
{
public getColour() : ?Colour;
}
interface iUserKettle extends iKettle
{
public canReadColour() : bool;
}
class Kettle implements iKettle
{
public getColour() : ?Colour
{
return this.colour;
}
}
class UserKettle extends Kettle implements iUserKettle
{
public UserKettle(....., UserKettleProperties props)
{
this.props = props;
}
public canReadColour() : bool
{
return this.props.canRead("colour");
}
public getColour() : ?Colour // override
{
if(this.canReadColour())
return super.getColour();
else
throw new Exception("You aren't allowed to know the colour");
}
}
canRead *方法的目的是明确知道属性是否可读。
假设您有一个Kettle字段,它返回一个值,也可以为空。 然后你做instance.getSomeProperty(),你得到NULL。但是你得到NULL是因为该值实际上是NULL或者因为你不允许读它?这就是你有第二个方法canReadSomeProperty()的原因,它告诉你是否允许你调用getter方法。
除了使用canRead *方法并抛出异常之外,您可能会考虑只返回NULL或null对象。
答案 3 :(得分:0)
这听起来像你只需要用户定义的自定义属性:
public class Kettle
{
public Dictionary<string, string> CustomProperties;
}
var kettle = new Kettle();
kettle.CustomProperties["Size"] = "1";
kettle.CustomProperties["Content"] = "Some Content";
kettle.CustomProperties["DateFermentationStarted"] = "1/1/2014";
您可以将这些属性保存在数据库中,作为单个客户的键/值对。然后创建配置GUI或XML配置文件以定义每个安装的自定义属性。在系统中创建Kettle对象时,您还将从所选的存储库中加载自定义属性。
这里的挑战是客户是否需要附加到这些属性的业务逻辑。由于属性是动态的,因此业务逻辑也需要是动态的(即插件,脚本等)。这会产生一系列不同的问题。