首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >依赖注入中接口的C#名称空间

依赖注入中接口的C#名称空间
EN

Stack Overflow用户
提问于 2016-02-28 22:01:33
回答 1查看 2K关注 0票数 1

我希望在Dependency Injection中使用C#模式,并且希望在名称空间中尽可能地将逻辑分隔开来。

问题

使用类的interface应该在哪个命名空间中?

问题的动机

首先,让我们做一些“正常”的情况。作为解释的第二部分的基础的书籍案例。然后是“现实生活”的案例,这就产生了问题。

书柜

让我们假设编码器是Alice,并且她使用Alice作为名称空间中的顶级名称作为供应商,以避免与其他编码器发生冲突。对于这个例子,我们假设世界上没有其他Alices。

让我们假设她创建了3个名称空间:

  • Alice.Invaders -一种通过商店提供应用程序内购买的游戏.
  • Alice.Shop -一家可重复使用的游戏商店。
  • Alice.Injector -一个可重用的服务管理器。

让我们假设Shop项目有一个名为IShopServiceinterface,它提供了一个方法Show()

让我们假设Invaders有某种控制器,在某些用户操作中想要打开商店。

让我们假设服务,像Shop一样,是由Invaders的控制器通过ServiceManager获得的。

Alice.Injector

Alice.Injector本身是一个没有依赖项的独立项目,因此它不使用"using“关键字:

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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 (以服务的形式),所以它都是干净的代码。

代码语言:javascript
运行
复制
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在他的项目中注入其他东西)。

代码语言:javascript
运行
复制
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接口(丑陋的是,她必须更改代码中的依赖项,因为它应该使用依赖项来消除代码中的依赖项)。
  • 没有接口的命名空间--如果Alice和Bob都在全局名称空间中设置了IShopService,它也很难看,因为有很多事情可能会发生冲突。
  • Alice.Shop 接口的名称空间--如果鲍勃利用常识,说“我想要做的是创建一个与兼容的商店,那么我应该实现她的接口”,所以Bob的代码很可能会像下面这样:

使用Alice.Shop向后命名空间兼容性的Bob代码:

代码语言:javascript
运行
复制
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.
        }
    }
}

在这种情况下,似乎一切都已就绪:

  • Bob可以创建实现Alice.Shop.IShopServiceAlice.Shop.IShopService
  • Alice不需要更改一行代码。
  • Alice.Injector.ServiceManager能够在为Bob.Shop.Shop服务时提供另一个IService

问题

这里仍然存在一种依赖关系:

Alice.InvadersAlice.Injector.IService转换为Alice.Shop.IShopService,以便能够调用Show()方法。如果你不做那个演员,你就不能“展示商店”。

因此,最终,您将“依赖”该强制转换,因此“某人”需要为您提供接口定义。

如果最初的商店不是由Alice编写的,而是由Charlie编写的,那么仍然需要下载和保存Charlie.Shop项目的副本才能使用Bob.Shop是“丑陋的”。

所以..。

问题

1) IShopInterface所使用的正确名称空间是什么?

( 2)“替换”项目是提供自己的接口还是借用原来的界面?

( 3)原来的店铺是否应该分拆成两个项目?(比如Alice.ShopAlice.ShopImplementation,所以Alice.Shop非常苗条,只包含接口?)也许Alice.ShopAlice.Shop.Implementation是嵌套的命名空间,但是仍然有两个分隔的代码库,这样您就可以在不下载Alice.Shop.Implementation的情况下下载ans安装Alice.Shop

4)是否就像Bob在他的项目中包含一个Alice.Shop.IShopInterface文件的副本一样简单,所以不需要依赖关系?很难看--如果他这么做了,我们想要有2家商店,把用户送到一家或另一家商店,那就会发生冲突。

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-29 08:34:33

接口、注入器和注入器应该在不同的名称空间中。接口应该在Alice.Shop.Interfaces中,并且在这个命名空间中不应该有任何内插。您可以更改/隐藏实现,但是您应该在依赖注入中坚持使用接口。

Alice.Invaders正在将Alice.Injector.IService转换为Alice.Shop.IShopService,以便能够调用Show()方法。如果你不做那个演员,你就不能“展示商店”。

你的DefaultController暗示不是很好。如果我想使用它,我不知道我需要什么服务。它对我说,我现在什么都不需要。

您应该使用构造函数注入。

代码语言:javascript
运行
复制
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进行注入。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35688838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档