Castle Windsor Ioc 一个接口多个实现解决方案
介绍
Castle Windsor 是微软的Ioc类库,本文主要介绍解决一个接口多个实现的解决方案
接口和类
以下内容不是真实的实际场景,仅仅是提供解决一个接口多个实现的思路。
业务场景类
先假设有一接口IHello
,该接口提供一个方法SayHello(string name)
,代码如下:
public interface IHello
{
void SayHello(string name);
}
这个接口有三个实现类,分别是ShanghaiHello
WuxiHello
和 BeijingHello
,代码如下
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解决解析的问题一直是我没想明白的问题,最近在工作中也遇到类似的,在使用模板方法
命令
等设计模式的时候,就遇到了一个接口多个实现这个之前一直没解决的内容。
一开始解决这个问题的时候,使用的是具体实现类,在到后来的工厂模式,文中介绍的几种解决方案也是我在解决实习问题中一一尝试的方案。
- 直接依赖实现类
- 扩展接口
2.1 具体工厂类
2.2 抽象工厂类- Named结合抽象工厂类
************转摘:https://www.jianshu.com/p/6154d565c3a3
Castle Windsor Ioc 一个接口多个实现解决方案的更多相关文章
- Castle.Windsor IOC/AOP的使用
Castle最早在2003年诞生于Apache Avalon项目,目的是为了创建一个IOC(控制反转)框架.发展到现在已经有4个组件了,分别是ActiveRecord(ORM组件).Windsor(I ...
- 在ASP.NET MVC中使用Castle Windsor
平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其在ASP.NET MVC中的应用过程. Visual Studio 2012创建一个ASP.NET MVC 4网站. ...
- ASP.NET MVC Castle Windsor 教程
一.[转]ASP.NET MVC中使用Castle Windsor 二.[转]Castle Windsor之组件注册 平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其 ...
- 10分钟 Castle.Windsor 适配 Asp.Net Core 3.0
Asp.Net Core 3.0以上,不再能通过修改Starup.ConfigureServices返回值(IServiceProvider),所以只能调用IHostBuilder.UseServic ...
- .net aop 操作 切面应用 Castle.Windsor框架 spring 可根据接口 自动生成一个空的实现接口的类
通过unget 安装Castle.Windsor using Castle.DynamicProxy; using System; using System.Collections.Generic; ...
- IoC - Castle Windsor 2.1
找过一些Windsor教程的文章,博客园上TerryLee有写了不少,以及codeproject等也有一些例子,但都讲的不太明了.今天看到Alex Henderson写的一个系列,非常简单明了.下面是 ...
- 小白初学Ioc、DI、Castle Windsor依赖注入,大神勿入(不适)
过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下 ...
- 多个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. ...
- Castle Windsor常用介绍以及其在ABP项目的应用介绍
最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载 ...
随机推荐
- 【linux学习笔记四】文件搜索命令
一 文件搜索 locate //在后台数据库中按文件名搜索 搜索速度更快 locate 文件名 //locate命令所搜索的后台数据库 /var/lib/mlocate //更新数据库 updated ...
- PS更换证件照背景颜色
同学们大家好,我是阿宝老师,今天给大家讲一下如何使用PS更换证件照背景色. 目前使用PS更换证件照底片有三种方式,这三种方式虽有不同,但是最终目的都是将人像从背景中抠出来.扣取人像有三种方法可供选取, ...
- [C语言]小知识点 持续更新
2019-11-24 1.如果输入: printf(,)); 会得到0: 这和我们的日常判断不相符! 然而,改成: printf(,)); 就可以成功输出“2”: 因此,注意pow函数返回的是浮点数, ...
- conda 创建tensorflow虚拟环境后,无法import tensorflow在jupyter
ensorflow安装好了,在python中也测试过了,但在jupyter中却会报错,原因是先装的Anaconda 之后装的tensorflow,所以环境有问题,所以需要重装jupyter,先激活te ...
- Android持久化存储——(包含操作SQLite数据库)
<第一行代码>读书手札 你可能会遇到的问题:解决File Explorer 中无显示问题 Android中,持久化存储,常见的一共有三种方法实现 (一.)利用文件存储 文件存储是Andro ...
- STM32F103芯片SPI控制NRF24L012.4G无线模块交互通信实验
1.NRF24L01模块的资料百度搜索一下就有很多.这里我就不做介绍本文主要侧重于应用层面实验介绍与分享. 2.先看下原理图. 根据原理图:写出NRF24L01 C语言驱动文件如下: #includ ...
- Oracle 11g xe版本---总结1
一.创建用户和授予权限 1.1 环境: Oracle 11g xe 第三方图形客户端: PLSQL Windows 10 必须登录 HR 用户,下面的查询会使用到 HR 中的表. 1.2 SQL 语句 ...
- 2019杭电多校三 C. Yukikaze and Demons (点分治)
大意: 给定树, 每个点有一个十进制数位, 求有多少条路径组成的十进制数被$k$整除. 点分治, 可以参考CF715C, 转化为求$10^a x+b\equiv 0(mod\space k)$的$x$ ...
- C++ 去掉字符串的首尾空格和全部空格
#include <iostream>#include <string>using namespace std; //去掉收尾空格string& ClearHeadTa ...
- python练习:面向对象1
面向对象习题: 一:定义一个学生类.有下面的类属性: 1 姓名 2 年龄 3 成绩(语文,数学,英语)[每课成绩的类型为整数] 类方法: 1 获取学生的姓名:get_name() 返回类型:str 2 ...