介绍

Castle Windsor 是微软的Ioc类库,本文主要介绍解决一个接口多个实现的解决方案

接口和类

以下内容不是真实的实际场景,仅仅是提供解决一个接口多个实现的思路。

业务场景类

先假设有一接口IHello,该接口提供一个方法SayHello(string name),代码如下:

public interface IHello
{
void SayHello(string name);
}

这个接口有三个实现类,分别是ShanghaiHello WuxiHelloBeijingHello,代码如下

public class ShanghaiHello : IHello
{
public void SayHello(string name)
{
Console.WriteLine($"{name},欢迎来到上海");
}
} public class WuxiHello : IHello
{
public void SayHello(string name)
{
Console.WriteLine($"{name},欢迎来到无锡");
}
} public class BeijingHello : IHello
{
public void SayHello(string name)
{
Console.WriteLine($"{name},欢迎来到北京");
}
}

初始化Ioc容器并且注册 IHello

// 初始化Ioc容器
IWindsorContainer _container= new WindsorContainer(); _container.Register(Component.For<IHello>().ImplementedBy<ShanghaiHello>(),
          Component.For<IHello>().ImplementedBy<WuxiHello>(),
          Component.For<IHello>().ImplementedBy<BeijingHello>());

从容器中获取IHello

var shanghaiHello = _container.Resolve<IHello>();
shanghaiHello.SayHello("武侯"); var wuxiHello = _container.Resolve<IHello>();
wuxiHello.SayHello("武侯");

运行结果

通过运行结果可知,虽然将三个实现类注入到Ioc容器中,但是通过Ioc解析IHello时,发现只能解析到第一条注册的组件,即ShanghaiHello


方案一:使用具体实现类(不推荐)

具体的思路是将实现类作为Windsor的服务注入,虽然该方案可以解决,但是这样做会依赖实现类型。

注册代码

修改注册代码,将具体的实现类作为服务注册

_container.Register(Component.For<IHello,ShanghaiHello>().ImplementedBy<ShanghaiHello>(),
  Component.For<IHello,WuxiHello>().ImplementedBy<WuxiHello>(),
  Component.For<IHello,BeijingHello>().ImplementedBy<BeijingHello>());

解析使用代码

            var shanghaiHello = _container.Resolve<ShanghaiHello>();
shanghaiHello.SayHello("武侯"); var wuxiHello = _container.Resolve<WuxiHello>();
wuxiHello.SayHello("武侯"); var beijingHello = _container.Resolve<BeijingHello>();
beijingHello.SayHello("武侯");

运行结果

 

方案二:扩展接口(推荐)

思路是针对三个实现类分别写接口,继承IHello,接口内容为空

接口

public interface IShanghaiHello : IHello
{
} public interface IWuxiHello : IHello
{
} public interface IBeijingHello : IHello
{
}

修改实现

public class ShanghaiHello : IShanghaiHello
{
public void SayHello(string name)
{
Console.WriteLine($"{name},欢迎来到上海");
}
} public class WuxiHello : IWuxiHello
{
public void SayHello(string name)
{
Console.WriteLine($"{name},欢迎来到无锡");
}
} public class BeijingHello : IBeijingHello
{
public void SayHello(string name)
{
Console.WriteLine($"{name},欢迎来到北京");
}
}

修改注册方式

_container.Register(Component.For<IHello,IShanghaiHello>().ImplementedBy<ShanghaiHello>(),
  Component.For<IHello,IWuxiHello>().ImplementedBy<WuxiHello>(),
  Component.For<IHello,IBeijingHello>().ImplementedBy<BeijingHello>());

使用

      var shanghaiHello = _container.Resolve<IShanghaiHello>();
shanghaiHello.SayHello("武侯"); var wuxiHello = _container.Resolve<IWuxiHello>();
wuxiHello.SayHello("武侯"); var beijingHello = _container.Resolve<IBeijingHello>();
beijingHello.SayHello("武侯");

运行结果

 

通过扩展自定义接口,也可以达到目的


基于方案二,工厂模式实现类(不推荐)

方法2解决了不需要依赖具体实现类的弊端,但是每次客户端调用都需要依赖容器,因此我们可以添加一个工厂,封装Ioc的解析过程

工厂实现

public class HelloFactoryOne
{
private readonly IWindsorContainer _container; public HelloFactoryOne(IWindsorContainer container)
{
this._container = container;
} public IHello Create<T>() where T : IHello
{
return this._container.Resolve<T>();
}
}

解析调用

      var factoryOne = new HelloFactoryOne(_container);

            var shanghaiHello = factoryOne.Create<IShanghaiHello>();
shanghaiHello.SayHello("武侯"); var wuxiHello = factoryOne.Create<IWuxiHello>();
wuxiHello.SayHello("武侯"); var beijingHello = factoryOne.Create<IBeijingHello>();
beijingHello.SayHello("武侯");

运行结果

 

基于方案二,工厂模式--接口(推荐)

该方案基于Castle Windsor的AsFactory方法

工厂接口

public interface IHelloFactory
{
IHello Create<T>() where T : IHello;
}

注意:该接口是没有任务实现的,注入的时候,使用AsFactory方式,Windsor会自动帮助我们创建实现

注册工厂接口

 // AsFactory方法必须要加这句
_container.AddFacility<TypedFactoryFacility>();
_container.Register(Component.For<IHello,IShanghaiHello>().ImplementedBy<ShanghaiHello>(),
        Component.For<IHello,IWuxiHello>().ImplementedBy<WuxiHello>(),
        Component.For<IHello,IBeijingHello>().ImplementedBy<BeijingHello>(),
        // 注册工厂接口
        Component.For<IHelloFactory>().AsFactory());

使用

      var factory = _container.Resolve<IHelloFactory>();
var shanghaiHello1 = factory.Create<IShanghaiHello>();
shanghaiHello1.SayHello("诸葛亮");
var wuxiHello1 = factory.Create<IWuxiHello>();
wuxiHello1.SayHello("诸葛亮");
var beijingHello1 = factory.Create<IBeijingHello>();
beijingHello1.SayHello("诸葛亮");

运行结果

 

方案三:使用Namd结合工厂接口(墙裂推荐)

方案二虽然可以解决一个接口对应多个实现的问题,但是需要扩展接口,如何不扩展接口,又能实现我们的需求呢?答案是注册的时候使用Named,并且解析AsFactory功能

修改注册

主要是给每个注册实例添加Named别称

      // AsFactory方法必须要加这句
_container.AddFacility<TypedFactoryFacility>();
_container.Register(Component.For<IHello,IShanghaiHello>().ImplementedBy<ShanghaiHello>().Named("Shanghai"),
        Component.For<IHello,IWuxiHello>().ImplementedBy<WuxiHello>().Named("Wuxi"),
         Component.For<IHello,IBeijingHello>().ImplementedBy<BeijingHello>().Named("Beijing"),
        // 注册工厂接口
         Component.For<IHelloFactory>().AsFactory());

扩展IHelloFactory接口

给三个实现类添加对应的获取方法

public interface IHelloFactory
{
IHello Create<T>() where T : IHello; /// <summary>
/// 方法名必须是 Get[Named]格式
/// </summary>
/// <returns></returns>
IHello GetShanghai(); /// <summary>
/// 方法名必须是 Get[Named]格式
/// </summary>
/// <returns></returns>
IHello GetWuxi(); /// <summary>
/// 方法名必须是 Get[Named]格式
/// </summary>
/// <returns></returns>
IHello GetBeijing();
}

使用

      var factory2 = _container.Resolve<IHelloFactory>();
var shanghaiHello2 = factory2.GetShanghai();
shanghaiHello2.SayHello("刘皇叔");
var wuxiHello2 = factory2.GetWuxi();
wuxiHello2.SayHello("刘皇叔");
var beijingHello2 = factory2.GetBeijing();
beijingHello2.SayHello("刘皇叔");

运行结果

 

总结

一个接口多个实现在设计中是经常会遇到的问题,如何通过Ioc解决解析的问题一直是我没想明白的问题,最近在工作中也遇到类似的,在使用模板方法 命令 等设计模式的时候,就遇到了一个接口多个实现这个之前一直没解决的内容。
一开始解决这个问题的时候,使用的是具体实现类,在到后来的工厂模式,文中介绍的几种解决方案也是我在解决实习问题中一一尝试的方案。

  1. 直接依赖实现类
  2. 扩展接口
    2.1 具体工厂类
    2.2 抽象工厂类
  3. Named结合抽象工厂类

************转摘:https://www.jianshu.com/p/6154d565c3a3

Castle Windsor Ioc 一个接口多个实现解决方案的更多相关文章

  1. Castle.Windsor IOC/AOP的使用

    Castle最早在2003年诞生于Apache Avalon项目,目的是为了创建一个IOC(控制反转)框架.发展到现在已经有4个组件了,分别是ActiveRecord(ORM组件).Windsor(I ...

  2. 在ASP.NET MVC中使用Castle Windsor

    平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其在ASP.NET MVC中的应用过程. Visual Studio 2012创建一个ASP.NET MVC 4网站. ...

  3. ASP.NET MVC Castle Windsor 教程

    一.[转]ASP.NET MVC中使用Castle Windsor 二.[转]Castle Windsor之组件注册 平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其 ...

  4. 10分钟 Castle.Windsor 适配 Asp.Net Core 3.0

    Asp.Net Core 3.0以上,不再能通过修改Starup.ConfigureServices返回值(IServiceProvider),所以只能调用IHostBuilder.UseServic ...

  5. .net aop 操作 切面应用 Castle.Windsor框架 spring 可根据接口 自动生成一个空的实现接口的类

    通过unget 安装Castle.Windsor using Castle.DynamicProxy; using System; using System.Collections.Generic; ...

  6. IoC - Castle Windsor 2.1

    找过一些Windsor教程的文章,博客园上TerryLee有写了不少,以及codeproject等也有一些例子,但都讲的不太明了.今天看到Alex Henderson写的一个系列,非常简单明了.下面是 ...

  7. 小白初学Ioc、DI、Castle Windsor依赖注入,大神勿入(不适)

    过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下 ...

  8. 多个IoC容器适配器设计及性能测试(Castle.Windsor Autofac Spring.Core)

    [转]多个IoC容器适配器设计及性能测试和容器选择 1. 采用的IoC容器和版本 Autofac.2.6.3.862 Castle.Windsor.3.1.0 Spring.Core.2.0.0 2. ...

  9. Castle Windsor常用介绍以及其在ABP项目的应用介绍

    最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载 ...

随机推荐

  1. Apache POI操作pptx基本使用

    最近有一个ppt操作的需求,因此查了下相关的资料 ppt分类 (1)2007版之前的 是基于二进制的文件格式 细节没有完全公开,第三方厂商多是用单向工程方法猜测和分析出来的.WPS做得好一些,但开源的 ...

  2. art-template 弹出编辑

    <!-- 模板 --> <script id="render-tpl" type="text/html"> <div class= ...

  3. How to change default root@ email address linux / postfix / centos?

    Change root@hostname to different email address By default, any email sent by system is sent to root ...

  4. windows 下搭建go开发环境

    下载golang安装包: 步骤一: 先打开环境变量配置的界面 步骤二;配置我们的环境变量 对上图的一个说明: 1).path这个变量不需要再创建,因为系统本就有,在后面添加即可. 2).增加Go的bi ...

  5. Qt:用 __thread 关键字让每个线程有自己的全局变量

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wsj18808050/article/d ...

  6. ubuntu下使用eclipse调试jni无法获取环境变量,本地库(java.library.path,LD_LIBRARY_PATH)等问题的解决。

    首先要把本地库全部配置到LD_LIBRARY_PATH中. 然后一定要采用命令行方式启动eclipse(也可以写一个启动shell,通过桌面启动器打开这个shell),这样环境变量才会有效. 打开终端 ...

  7. hdu 1075 map的使用 字符串截取的常用手段 以及string getline 使用起来的注意事项

    首先说字符串的截取套路吧 用坐标一个一个的输入 用遍历的方式逐个去检查字符串中的字符是否为符合的情况 如果是的话 把该字符放入截取string 中 让后坐标前移 如果不是的话 截取结束 坐标初始化 然 ...

  8. OSS服务和自建服务器存储对比

    1 OSS 1.1 什么是OSS   阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云提供的海量.安全.低成本.高可靠的云存储服务.它是一个分布式的对象存储服务 ...

  9. 代码审计:covercms 1.6

    小菜只能找找没人用的cms练练手了 cnvd上有个 CoverCMS V1.16存在多个漏洞 漏洞描述 :CoverCMS V1.16存在重装.信息泄露.暴力破解.存储型跨站脚本和反射型跨站脚本漏洞. ...

  10. C#在txt类文件中追加内容

    string path = "test.txt"; FileStream mystream = new FileStream(path, FileMode.OpenOrCreate ...