4

我已经构建了一个开源应用程序,我很想知道其他人如何处理客户特定的请求。让应用程序保持简单对我来说很重要;我并不是想为所有人创造一切。以这种方式,应用程序可能会变得臃肿、复杂并且几乎无法使用。但是,有一些特定于客户的选项会很好(它只是不适用于所有客户)。例如...

假设我们有一个名为 Server 的域实体。在 UI 中,我们让客户从服务器列表中进行选择。对于一家公司,按位置(美国、德国、法国等)过滤服务器会很有帮助。添加这样的服务器属性很容易:

public class Server
{
    public Location Location { get; set; }
    // other properties here
}

我担心的是,随着时间的推移,服务器可能会因属性而变得臃肿。即使我只添加位置,也不是所有客户都会关心该属性。

一种选择是允许用户定义的字段:

public class Server
{
    public string UserField1 { get; set; }
    public string UserField2 { get; set; }
    public string UserField3 { get; set; }
    // etc...
    // other properties here
}

这是处理这个问题的最好方法吗?我不喜欢通过将所有内容都设为字符串来消除类型安全性的事实。人们是否有其他/更好的方式来处理此类问题?甚至有这样的设计模式吗?

4

6 回答 6

2

在我看来,一个好的设计模式是在数据库级别使用模式,然后在类级别使用基本继承。

CREATE TABLE dbo.A (
    ColumnA INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    ColumnB VARCHAR(50),
    ColumnC INT,
    etc.
)

现在我们有一个需要一些特定功能的客户端,所以让我们在不同的模式中创建这个表的扩展:

CREATE TABLE CustomerA.A (
    ColumnA INT NOT NULL PRIMARY KEY,
    Location VARCHAR(50)
)

但是现在我们有另一个客户需要以不同的方式扩展它:

CREATE TABLE CustomerB.B (
    ColumnA INT NOT NULL PRIMARY KEY,
    DataCenterID INT
)

尽管这些字段可能不相关,但您明白了,所以现在我们需要在这里构建客户特定的域模型:

public abstract class A
{
    public int ColumnA { get; set; }
    public string ColumnB { get; set; }
    public int ColumnC { get; set; }
}

public class CustomerA_A : A
{
    public string Location { get; set; }
}

public class CustomerB_A : A
{
    public int DataCenterID { get; set; }
}

因此,现在当我们需要为客户 A 构建某些东西时,我们将构建他们的子类,并为客户 B 构建他们的子类,依此类推。

现在,仅供参考,这是一个非常动态的系统的开始。我之所以这么说,是因为缺少的那部分还不是动态的,是用户界面。有很多方法可以完成,但超出了这个问题的范围。这是你必须考虑的事情。我这么说是因为你管理接口的方式将决定你如何知道构建哪个子类。

我希望这有帮助。

于 2012-12-05T20:45:01.060 回答
1

早期的常用方法是使用配置 XML 文件来处理这类事情。但是针对特定客户的需求进行编程需要围绕您的编程方式进行全面思考。请参阅this answer到类似的问题。

于 2012-12-05T20:45:41.120 回答
1

当然,这始终取决于您要允许多少自定义。在我们的产品中,我们甚至使用户能够完全定义他们自己的实体以及它们之间的属性和关系。基本上,我们称之为实体的每个 EntityObject 最终都包含一个值集合和对描述其中值的元模型的引用。我们设计了自己的查询语言,允许我们查询数据库并使用可翻译成任何目标语言的表达式(尽管我们目前只使用 SQL 和 .net)。

游戏并没有就此结束,您很快就会发现验证规则、权限、默认值等成为必须具备的。当然,所有这些都需要 UI 支持,至少对于元模型的执行而言。

因此,这实际上取决于最终用户应该能够执行的调整量。我猜在大多数情况下,如您所描述的,简单的用户字段就足够了。在这种情况下,我将提供一个字段并在其中存储 JSON 文本。然后,在 UI 中,您可以提供至少一个允许结构和可扩展性的半体面的 UI。

于 2012-12-05T20:51:37.913 回答
1

选项1:说“不”。:-)

虽然我这么说(一半)是开玩笑的,但这是有道理的。开发人员经常通过允许一两个自定义功能来让自己接受无休止的自定义,从而使雪球滚滚而来。

当然,这必须是平衡的,听起来你可能在某种程度上这样做了。但是如果你真的想让你的应用程序简单,那就保持简单,避免添加这样的自定义。

选项2:继承。

如果您真的需要添加自定义,我会倾向于构建具有所有“标准”选项的基类,然后构建包含客户特定优化的客户特定类。

例如:

public class Server
{
    // all standard properties here
}

那么对于 Joe's Pizza,您可以拥有:

public class JoesPizzaServer : Server
{
    public Location Location { get; set; }
}

这样做的附带好处是,它将允许您基于特定于客户端(或基本)模型的演示视图。

例如,在 MVC 中,您可以像这样设置视图模型,然后您可以为每个客户提供特定的视图。

例如,Bob's Burgers 对基本模型有自己的看法:

@model MyApp.Server
@* implement the base form *@

Joe's Pizza 的视图将使用自定义模型:

@model MyApp.JoesPizza
@* implement the base form -- a partial view -- with addtional custom fields

MVC 在支持这种模式方面做得非常好。如果您不使用 MVC(可能是 WPF 或 Web 窗体),仍然有一些方法可以利用部分“视图”文件来完成类似的事情。

当然,您的数据库可以(并且可能应该)支持类似的继承模型。Entity Framework 甚至支持像这样的各种继承模型。

于 2012-12-05T20:55:37.067 回答
1

我在这里可能错了,但看起来您想使用相同的代码库处理不同版本的软件。我可以想到两种方法:

  1. 实际上为它定义不同的版本并为每个客户端处理更改。从域建模的角度来看,这不会给您带来问题,但需要一个支持基础架构,该基础架构必须根据您的客户要求进行扩展。有一些相关的问题(例如thisthisthis)。
  2. 在域模型级别处理它,作为用户定义的配置。这种方法的优点是您不必合并软件的多个版本,但这是以使您的模型更通用且可能更复杂为代价的。此外,您的测试肯定必须适应处理不同的场景。如果您朝着那个方向前进,我将建模一个表示属性的对象(带有名称和值)并将Server类视为具有属性的集合。这样,您的模型仍然以 OO 风格捕获您的需求。

高温高压

于 2012-12-05T20:56:26.537 回答
0

我从 Python 接近,我认为会很好听的是字典。键是您的字段名称,值是 errrrr... 值;)

在数据库中表示也很简单。

于 2012-12-05T21:50:52.717 回答