我希望在Dependency Injection
中使用C#模式,并且希望在名称空间中尽可能地将逻辑分隔开来。
问题
使用类的interface
应该在哪个命名空间中?
问题的动机
首先,让我们做一些“正常”的情况。作为解释的第二部分的基础的书籍案例。然后是“现实生活”的案例,这就产生了问题。
书柜
让我们假设编码器是Alice,并且她使用Alice
作为名称空间中的顶级名称作为供应商,以避免与其他编码器发生冲突。对于这个例子,我们假设世界上没有其他Alices。
让我们假设她创建了3个名称空间:
Alice.Invaders
-一种通过商店提供应用程序内购买的游戏.Alice.Shop
-一家可重复使用的游戏商店。Alice.Injector
-一个可重用的服务管理器。让我们假设Shop
项目有一个名为IShopService
的interface
,它提供了一个方法Show()
。
让我们假设Invaders
有某种控制器,在某些用户操作中想要打开商店。
让我们假设服务,像Shop
一样,是由Invaders
的控制器通过ServiceManager
获得的。
Alice.Injector
Alice.Injector
本身是一个没有依赖项的独立项目,因此它不使用"using“关键字:
namespace Alice.Injector
{
public interface IService
{
// All the services shall implement this interface.
// This is necessary as C# is heavily typed and the
// Get() method below must return a known type.
}
public class ServiceManager
{
static public IService Get( string serviceName )
{
IService result;
// Do the needed stuff here to get the service.
// Alice implements this getter configurable in a text-file
// so if she wants to test the invaders with a mock-shop
// that does not do real-purchases but fake-ones
// she can swap the injected services without changing the
// consumer's code.
result = DoTheNeededStuff();
return result;
}
}
}
Alice.Shop
Alice.Shop
也是一个独立的项目(在它使用服务的情况下除外),它不知道注入器的存在。只是一家商店,就这样。
当Alice认为鲍伯有一天可能会做一些更好的工作时,她会在将Shop
分离成一个接口IShop
之后,然后按照本文:https://msdn.microsoft.com/library/hh323705%28v=vs.100%29.aspx的实现,为自己的类做好准备。
为了实现这一点,艾丽斯将使商店成为一种与Alice.ServiceManager
兼容的服务,因此爱丽丝决定将IShop
重命名为IShopService
,它将是一种IService
。
using Alice.Injector
namespace Alice.Shop
{
public interface IShopService : IService
{
public void Show();
}
public class Shop : IShopService
{
public void Show()
{
// Here Alice puts all the code to open the shop up.
}
}
}
Alice.Invaders
最后爱丽丝对游戏进行了编码。Alice.Invaders
的代码通过ServiceManager
获得一个Shop
(以服务的形式),所以它都是干净的代码。
using Alice.Injector
using Alice.Shop
namespace Alice.Invaders
{
public class DefaultController
{
void OnShopClick()
{
IShopService shop = ServiceManager.Get( "Shop" ) as IShopService;
shop.Show();
}
}
}
到现在为止,这一切都很好。
现实生活案例
所以现在..。鲍勃(大家都知道,艾丽斯的一个好朋友,很好奇他们今天不会谈论发送电子邮件),他开了一家超级漂亮的商店,比艾丽斯做的还要好。鲍勃从无到有地做他的店。
因此,Bob实现了与Alice的注入器兼容的商店(因为Bob还使用Alice.Injector
在他的项目中注入其他东西)。
using Alice.Injector
namespace Bob.Shop
{
public interface IShopService : IService
{
public void Show();
}
public class Shop : IShopService
{
public void Show()
{
// Here Bob does a brand new shop from scratch.
}
}
}
所以..。这就是奇怪的情况!!
Bob.Shop
名称空间用于接口--如果Bob按照上面显示的方式在Bob.Shop
名称空间中操作,那么爱丽丝必须编辑她的代码以引用Bob.Shop
来获得IShopService
接口(丑陋的是,她必须更改代码中的依赖项,因为它应该使用依赖项来消除代码中的依赖项)。IShopService
,它也很难看,因为有很多事情可能会发生冲突。Alice.Shop
接口的名称空间--如果鲍勃利用常识,说“我想要做的是创建一个与兼容的商店,那么我应该实现她的接口”,所以Bob的代码很可能会像下面这样:使用Alice.Shop
向后命名空间兼容性的Bob代码:
namespace Bob.Shop
{
public class Shop : Alice.Shop.IShopService
{
public void Show()
{
// Here Bob does a brand new shop from scratch,
// which borrows Alice's interface.
}
}
}
在这种情况下,似乎一切都已就绪:
Alice.Shop.IShopService
的Alice.Shop.IShopService
。Alice.Injector.ServiceManager
能够在为Bob.Shop.Shop
服务时提供另一个IService
。问题
这里仍然存在一种依赖关系:
Alice.Invaders
将Alice.Injector.IService
转换为Alice.Shop.IShopService
,以便能够调用Show()
方法。如果你不做那个演员,你就不能“展示商店”。
因此,最终,您将“依赖”该强制转换,因此“某人”需要为您提供接口定义。
如果最初的商店不是由Alice编写的,而是由Charlie编写的,那么仍然需要下载和保存Charlie.Shop
项目的副本才能使用Bob.Shop
是“丑陋的”。
所以..。
问题
1) IShopInterface
所使用的正确名称空间是什么?
( 2)“替换”项目是提供自己的接口还是借用原来的界面?
( 3)原来的店铺是否应该分拆成两个项目?(比如Alice.Shop
和Alice.ShopImplementation
,所以Alice.Shop
非常苗条,只包含接口?)也许Alice.Shop
和Alice.Shop.Implementation
是嵌套的命名空间,但是仍然有两个分隔的代码库,这样您就可以在不下载Alice.Shop.Implementation
的情况下下载ans安装Alice.Shop
。
4)是否就像Bob在他的项目中包含一个Alice.Shop.IShopInterface
文件的副本一样简单,所以不需要依赖关系?很难看--如果他这么做了,我们想要有2家商店,把用户送到一家或另一家商店,那就会发生冲突。
谢谢。
发布于 2016-02-29 08:34:33
接口、注入器和注入器应该在不同的名称空间中。接口应该在Alice.Shop.Interfaces
中,并且在这个命名空间中不应该有任何内插。您可以更改/隐藏实现,但是您应该在依赖注入中坚持使用接口。
Alice.Invaders正在将Alice.Injector.IService转换为Alice.Shop.IShopService,以便能够调用Show()方法。如果你不做那个演员,你就不能“展示商店”。
你的DefaultController暗示不是很好。如果我想使用它,我不知道我需要什么服务。它对我说,我现在什么都不需要。
您应该使用构造函数注入。
public class DefaultController
{
private readonly IShopService _shopService;
DefaultController(IShopService shopService)
{
_shopService=shopService;
}
void OnShopClick()
{
_shopService.Show();
}
}
如果我需要默认控制器,我就会知道我需要哪些服务。你也不需要投。
编辑:
假设爱丽丝有一家商店。她说我想要一间有五把椅子的阅览室。但她会决定椅子是木头还是皮革(IChairs)。当她打开商店时,她决定使用木椅子(注入WoodChairs IChairs)。
然后鲍勃从爱丽丝那里买下了那家商店。他不能换阅览室(这很难,这需要时间,阅览室也很好)。但他想要皮椅,所以他用皮椅(Inject for IChairs)。
鲍勃应该坚持Alice.Shop.Interfaces
,如果他不能或不想改变阅览室。
但让我们说。我非常喜欢爱丽丝阅览室。我想设计一个和她一样的阅览室。但是我想为阅读室制定我的规则(IMyReadingRoom适配器,您得到ReadingRoom类而不是接口,并创建自己的接口)。
简单地说,():您应该始终坚持接口。您可以为第三方库创建自己的接口(适配器)。这样您就可以扩展或隐藏规则,而不必粘贴到第三方库(但无论如何,您应该坚持自己的界面)。您应该为第三方库定义编写适配器,而不是为它们的接口编写适配器。
如果我们跳过适配器选择,Bob必须使用Alice.Shop.Interfaces
进行注入。
https://stackoverflow.com/questions/35688838
复制相似问题