一个更好的架构然后如果(某事)DoIt()否则Dont()

时间:2015-08-23 11:12:00

标签: c# .net sql-server api infrastructure

我正在尝试创建一种机制,允许应用程序决定(在运行时)是否执行某些功能。

“一些功能”可以是任何东西,它可以是c#代码,它包含在几个dll中的几个类中,它可以是UI,也可以是数据库查询执行等。

最重要的是,它应该适合我现有的基础架构,我无法从头开始重新设计和构建。

我越是想到它,似乎我可以使用的唯一解决方案是保存一些表,它将是“功能存储库”,并且它将告诉(通过唯一键)功能是否打开/关闭。

然后在代码中,我将必须在每个处理此类功能的位置放置if else语句。

E.g。

If(functionalityEnabled)?
DoFunctionality()
Else
DoTheUsusal()

有没有更好的方法或更好的设计来实现它?我想让解决方案尽可能简单,但另一方面,这个解决方案真的很难看,最终会使我的代码看起来像意大利面条代码。

您的意见将不胜感激, 我正在使用c#和sql server,web api用于Web服务。

编辑:

我想说,我感谢每个人回答我的问题的时间和精力,你提出了一些非常有趣的想法。 我最终标记了@dasblinkenlight答案,因为它最适合需要,尽管其他答案非常好,可能对其他人有用。

谢谢。

5 个答案:

答案 0 :(得分:4)

如果您有两个实现相同接口的类,您的应用程序可以调用该类的功能(方法,属性),而无需确切地知道它是在调用基本功能还是替代功能:

IFunctionalityX {
  DoIt();
}

class BasicFunctionalityX: IFunctionalityX {
  public DoIt() {
    // Default behaviour goes here
  }
}

class PluginFunctionalityX: IFunctionalityX {
  public DoIt() {
    // Alternative functionality.
  }
}

如果PluginFunctionalityX与BasicFunctionalityX共享其部分实现,你可以从另一个继承它,但是否真的不重要。只要您使用界面,这就是重要的,无论类是否相关,您都可以使用此方法。

在程序初始化中,您可以做出一次决定并创建正确类的实例。您可以将此类存储在包含所有功能的容器中。 FunctionalityX是接口IFunctionalityX的属性,您可以为其他功能创建其他接口(和属性)。

if (functionalityXEnabled) {
  FunctionalityContainer.FunctionalityX = new PluginFunctionality();
} else {
  FunctionalityContainer.FunctionalityX = new BasicFunctionality();
}

然后,在您的应用程序的其余部分中,您可以通过以下方式调用您的功能:

FunctionalityContainer.FunctionalityX.DoIt();

您可以使用依赖注入库,而不是从头开始实现此操作,例如Unity。这也使您可以在需要时更轻松地获得正确功能的实例,而无需在程序开始时创建所有功能,也无需为所有功能编写精心构造的代码。

答案 1 :(得分:2)

您希望在运行时根据配置设置以不同方式调度代码。条件和多态是两种方式。

条件

在运行时,使用ifswitch或其他查找方法检查值。你已经在做这些了。

if (configFile.cloudAccount == null) {
    saveFileToDisk();
} else saveFileToCloud();

优点

  • 他们的条件,你真的不能避免在任何重要的开发项目中做某一个

缺点

  • 但是,在应用程序中每个点执行它们会很痛苦。因此,他们最好结合其他策略来尽量减少使用

多态性

加载应用程序时,请仔细阅读配置文件并构建应用程序的组件:

interface IFileSaver { /* Used to save files in your application */ }

class DiskSaver : IFileSaver { /* The default file saving class */ }

class CloudSaver : IFileSaver { /* If they've configured a cloud account */ }

// EXAMPLE USE

int Main (...) {
    // Setup your application, load a config file. 
    // You'll need to check the config with a conditional 
    // here (uh oh) but other components of your application 
    // will just use the IFileSaver interface
    if (configFile.cloudAccount != null) {
        YourApplication.FileSaver = new CloudSaver(configFile.cloudAccount);
    } else {
        YourApplication.FileSaver = new DiskSaver();
    }
}

// Somewhere else in your application
void SaveCurrentDocument() {
    // No if's needed, it was front loaded when initialising
    // the application
    YourApplication.FileSaver.Save();
}

优点

  • 非常适合面向对象的设计
  • 所有配置检查都是正面加载的。加载到正确的类后,程序的其余部分将使用它们,不知道它们的实际实现。因此,您不需要在整个代码中进行if检查。
  • 编译器将能够静态检查方法中的类型错误

缺点

  • 只有您班级的界面灵活。也许您希望使用CloudSaver进行一些额外的步骤和检查,它们更适合预先存在的界面;否则,他们不会发生。

长篇短篇 - 条件允许您在需要时明确执行检查,因此原则上您可以获得很多程序灵活性。例如,SaveAs例程可能需要以与Save例程不同的方式稍微保存文件 。但是,正如您所确定的那样,这会导致长重复的代码。在这些情况下,构建代码以使用多态可能会有所帮助。

无论哪种方式,只要您的应用程序具有灵活性,您几乎肯定需要一些量的条件检查。

注意:有许多实现运行时配置检查的其他方法,我只是指出最常见的(通常是直截了当的)

答案 2 :(得分:1)

如果它只是一个条件,那么你别无选择,只能使用if else,并且非常适合单一条件。

如果你有超过1个条件,你可以考虑使用Switch语句。

至于你担心你的代码看起来很复杂if else语句,把你的代码放在函数中,

if(condition)
{
  DoThis();
}
else
{
  DoSomethingElse();
}

答案 3 :(得分:1)

OO程序员曾经流行的一句话就是代码中的每个条件都表明错过了子类化的机会。虽然这个规则远非普遍存在,但在构图方面却不尽如人意,但它有一定道理,特别是当你看到同一条件出现在多个if的不同方法中时。同一个班级。

处理if之类的常见方法是使用继承和组合的某种组合,并将决策移动到创建对象的单个位置。

继承方式如下:

interface Doer {
    void doSomething();
}
class BasicDoer implements Doer {
    public void doSomething() {
        ...
    }
}
class EnhancedDoer extends BasicDoer {
    public void doSomething() {
        base.doSomething();
        ...
    }
}

// At construction time:

Doer doer;
if (someCondition)
    doer = new BasicDoer();
else
    doer = new EnhancedDoer();

构图方式如下:

interface Doer {
    void doSomething();
}
// Create several implementations of Activity, then...

// At construction time:
List<Doer> doers = new ArrayList<>();
if (someCondition1)
    doers.add(new SomeKindOfDoer());
if (someCondition2)
    doers.add(new AnotherKindOfDoer());
if (someCondition3)
    doers.add(new YetAnotherKindOfDoer());

现在代替if执行此操作:

for (Doer d : doers) {
    d.doSomething();
}

答案 4 :(得分:1)

如果功能不需要与对象数据进行大量交互(尽管可以进行交互),也许类似于strategy design pattern(行为的封装)会使其更易于管理。优点:可读的可扩展代码,缺点:代码很多。

100