Run*_*une 8 c# dependency-injection inversion-of-control
我和另外两位同事正试图了解如何最好地设计一个程序.例如,我有一个接口ISoda实现这样的接口和多个类Coke,Pepsi,DrPepper,等....
我的同事说,最好将这些项目放入数据库,如键/值对.例如:
Key | Name
--------------------------------------
Coke | my.namespace.Coke, MyAssembly
Pepsi | my.namespace.Pepsi, MyAssembly
DrPepper | my.namespace.DrPepper, MyAssembly
Run Code Online (Sandbox Code Playgroud)
...然后有XML配置文件,将输入映射到正确的密钥,查询数据库中的密钥,然后创建对象.
我没有任何具体原因,但我只是觉得这是一个糟糕的设计,但我不知道该说什么或如何正确地反对它.
我的第二位同事建议我们对这些课程进行微观管理.因此基本上输入将通过switch语句,类似于此:
ISoda soda;
switch (input)
{
case "Coke":
soda = new Coke();
break;
case "Pepsi":
soda = new Pepsi();
break;
case "DrPepper":
soda = new DrPepper();
break;
}
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎有点好,但我仍然认为有更好的方法来做到这一点.过去几天我一直在阅读IoC容器,这似乎是一个很好的解决方案.但是,我对依赖注入和IoC容器仍然很新,所以我不知道如何正确地争论它.或许我错了,有更好的方法吗?如果是这样,有人可以提出更好的方法吗?
我可以提出什么样的论据来说服我的同事尝试另一种方法?有哪些优点/缺点?我们为什么要这样做呢?
不幸的是,我的同事们非常不愿意改变,所以我想弄清楚如何说服他们.
编辑:
好像我的问题有点难以理解.我们要弄清楚的是如何最好地设计一个利用多个接口的应用程序,并包含许多实现这些接口的具体类型.
是的,我知道将这些东西存储在数据库中是一个坏主意,但我们根本不知道更好的方法.这就是为什么我问怎么做,我们做的更好.
public void DrinkSoda(string input)
{
ISoda soda = GetSoda(input);
soda.Drink();
}
Run Code Online (Sandbox Code Playgroud)
我们如何正确实施GetSoda?我们应该重新考虑整个设计吗?如果传递这样的魔法字符是个坏主意,那么我们应该怎么做呢?
用户输入诸如"Diet Coke","Coke","Coke Lime"或其他任何会实例化类型的输入Coke,因此多个关键字映射到单个类型.
很多人都说上面发布的代码很糟糕.我知道这很糟糕.我正在寻找理由向同事们展示并说明为什么这很糟糕以及为什么我们需要改变.
如果这个解释仍然难以理解,我深表歉意.我很难描述这种情况,因为我真的不明白如何用语言表达.
作为一般规则,传递包装概念的对象比传递字符串更加面向对象.也就是说,当您需要将稀疏数据(如字符串)转换为适当的域对象时,有很多情况(特别是在UI方面).
例如,您需要将字符串形式的用户输入转换为ISoda实例.
标准的,松散耦合的方式是使用抽象工厂.像这样定义:
public interface ISodaFactory
{
ISoda Create(string input);
}
Run Code Online (Sandbox Code Playgroud)
您的消费者现在可以依赖ISodaFactory并使用它,如下所示:
public class SodaConsumer
{
private readonly ISodaFactory sodaFactory;
public SodaConsumer(ISodaFactory sodaFactory)
{
if (sodaFactory == null)
{
throw new ArgumentNullException(sodaFactory);
}
this.sodaFactory = sodaFactory;
}
public void DrinkSoda(string input)
{
ISoda soda = GetSoda(input);
soda.Drink();
}
private ISoda GetSoda(input)
{
return this.sodaFactory.Create(input);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意Guard子句和readonly关键字的组合如何保证SodaConsumer类的不变量,它允许您使用依赖项而不必担心它可能为null.
我遇到过的对依赖注入的最好介绍实际上是Ninject wiki 网站上的一系列快速文章,这些文章构成了概念的演练。
您并没有真正给出有关您想要完成的任务的太多背景信息,但在我看来,您正在尝试设计一个“插件”架构。如果是这种情况 - 你的感觉是正确的 - 这两种设计总而言之,太糟糕了。第一个相对较慢(数据库和反射?),对数据库层有大量不必要的依赖,并且不会随程序扩展,因为每个新类都必须输入数据库。只使用反射有什么问题?
第二种方法几乎无法扩展。每次引入新类时,旧代码都必须更新,并且必须“了解”您将插入的每个对象 - 这使得第三方无法开发插件。您添加的耦合,即使使用定位器模式之类的东西,也意味着您的代码不够灵活。
这可能是使用依赖注入的好机会。阅读我链接的文章。关键思想是依赖注入框架将使用配置文件来动态加载您指定的类。这使得交换程序的组件变得非常简单和直接。
| 归档时间: |
|
| 查看次数: |
3614 次 |
| 最近记录: |