我正在尝试创建一种机制,允许应用程序决定(在运行时)是否执行某些功能。
“一些功能”可以是任何东西,它可以是c#代码,它包含在几个dll中的几个类中,它可以是UI,也可以是数据库查询执行等。
最重要的是,它应该适合我现有的基础架构,我无法从头开始重新设计和构建。
我越是想到它,似乎我可以使用的唯一解决方案是保存一些表,它将是“功能存储库”,并且它将告诉(通过唯一键)功能是否打开/关闭。
然后在代码中,我将必须在每个处理此类功能的位置放置if else语句。
E.g。
If(functionalityEnabled)?
DoFunctionality()
Else
DoTheUsusal()
有没有更好的方法或更好的设计来实现它?我想让解决方案尽可能简单,但另一方面,这个解决方案真的很难看,最终会使我的代码看起来像意大利面条代码。
您的意见将不胜感激, 我正在使用c#和sql server,web api用于Web服务。
编辑:
我想说,我感谢每个人回答我的问题的时间和精力,你提出了一些非常有趣的想法。 我最终标记了@dasblinkenlight答案,因为它最适合需要,尽管其他答案非常好,可能对其他人有用。
谢谢。
答案 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)
您希望在运行时根据配置设置以不同方式调度代码。条件和多态是两种方式。
在运行时,使用if
,switch
或其他查找方法检查值。你已经在做这些了。
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