代码库中的客户特定要求

时间:2013-08-08 09:31:18

标签: design-patterns architecture

在代码库中实施小客户特定更改时,您如何处理以及最佳实践?

此特定产品由10-20位客户使用,并作为Web应用程序提供。当一个客户想要其他客户不想要或没有购买的特定功能时,我发现很难管理并且不会使代码混乱。

我已经查看了使用if语句解决此问题的早期代码:

if(customerId == Customer.One) {
 // code goes here...
}

if(customer.hasThisSpecificFeature()) {
 // code goes here.
 }

问题在于,当具有多个特定功能时,很难维护。代码不可读且难以调试。

有没有一种良好而干净的方法来解决这个问题?

2 个答案:

答案 0 :(得分:1)

进一步阅读:Strategy Pattern; Template Method Pattern; Inversion of Control(IoC)。

这样做的一种方法是提取必须监听客户特定功能的逻辑并注入实现,而不是将其烘焙到代码中。例如,使用界面:

public int GetAge(Person p)
{
    return p.Age;
}

顾客想要撒谎,所以要求你为所有年龄段添加1:

public int GetAge(Person p)
{
    var age = p.Age;

    // Imagine all this exists...
    if (CustomerContext.CurrentCustomer == Customer.One)
    {
        age++;
    }

    return age;
}

这个想法是提取年龄的后处理:

public int GetAge(Person p, IAgePostProcessor ageProcessor)
{
    var age = p.Age;
    return ageProcessor.Process(age);
}

public interface IAgePostProcessor
{
    int Process(int age);
}

然后,除此之外,当您知道自己的客户环境时,您可以决定在启动时配置一次策略。

对于那个客户,您提供了一个+ 1s年龄的实现,为您提供的其他所有人都提供了无效的传递实现。

您可以利用其他DI / IoC框架(Ninject,Castle Windsor,StructureMap)来帮助管理这些东西。

<小时/> 或者,您的“界面”可以只是Func<int, int>

public int GetAge(Person p, Func<int, int> postProcessAge)
{ 
    if (postProcessAge == null)
        postProcessAge = a => a; // Do nothing.

    return postProcessAge(p.Age);
}

这再次将依赖项移到此方法之外,并允许您在其他地方做出逻辑决策,可能在启动时集中一次。

<小时/> 所有方法的好处是,您可以独立于用于证明每个客户满足验收标准的位置来测试客户特定的实施。

答案 1 :(得分:0)

我认为开发人员应远离客户特定代码

如果您允许对产品进行自定义,则应抽象出自定义,以便任何客户端都可以针对其特定安装更改自定义/功能的“设置”。即使该功能是全新功能,也会为您的产品添加新功能,并且您希望为您的任何客户带来同样的好处。

这些自定义的设置应包含在配置文件或数据库表中。这允许任何客户使用您正在构建的功能,并允许每个客户将设置更改为他们的要求,而无需更改代码和重新部署。

它可能会提前做一些工作,但会使您的代码库不会因为每个客户的自定义而变得混乱,并且可以更轻松地对功能进行调整/调整。