介绍

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. AWS 数据库(七)

    数据库概念 关系型数据库 关系数据库提供了一个通用接口,使用户可以使用使用 编写的命令或查询从数据库读取和写入数据. 关系数据库由一个或多个表格组成,表格由与电子表格相似的列和行组成. 以行列形式存储 ...

  2. 简简单单储存过程——循环一个select结果集

    原文地址:https://shitou521.iteye.com/blog/1069027 摘要:本文主要讲解了存储过程的创建.调用.以及游标的使用 ,相信掌握了游标      会对你有不错的帮助,有 ...

  3. Keras.NET

    [翻译]Keras.NET简介 - 高级神经网络API in C#   Keras.NET是一个高级神经网络API,它使用C#编写,并带有Python绑定,可以在Tensorflow.CNTK或The ...

  4. eNSP下配置Trunk接口实现跨交换机传递数据

    当Trunk端口发送数据帧的时候,当所发送帧的VLAN ID与端口的PVID不同是,检查是否允许该VLAN通过,若允许的话,直接透传,不允许就直接丢弃:当该帧的VLAN ID与端口的PVID相同时,则 ...

  5. jenkins最新版下载安装

    前提:安装配置 jetty 在线下载jetty# wget http://download.eclipse.org/jetty/8.1.17.v20150415/dist/jetty-distribu ...

  6. Mowing the Lawn【线性dp + 单调队列优化】

    题目链接:https://ac.nowcoder.com/acm/contest/2652/G 题目大意:与上一篇博客 烽火传递 差不多. 1.一共n头羊,若超过m头连续的羊在一起,就会集体罢工,每头 ...

  7. php 文字转换成拼音

    <?php //中文字转拼音 $d=array( array("a",-20319), array("ai",-20317), array("a ...

  8. 八皇后问题——列出所有的解,可推至N皇后

    <数据结构>--邓俊辉版本 读书笔记 今天学习了回溯法,有两道习题,一道N皇后,一道迷宫寻径.今天,先解决N皇后问题.由于笔者 擅长java,所以用java重现了八皇后问题. 注意是jav ...

  9. 用php的for循环输出四边形,各种三角形和菱形【含空心版本】

    <?php // 实心版 //四边形 for( $i = 1; $i <=5; $i++ ){ for( $j = 1; $j <=5; $j++ ){ echo '*'; } ec ...

  10. hadoop 节点退役和服役

    节点的服役和退役(hdfs)---------------------- 黑白名单的组合情况-------------------------include //dfs.includeexclude ...