怎么着铲除具体注重,关于信赖注入IOC

    /// <summary>

    /// 订单实体

    /// </summary>

    class Order

    {

 

    }

 

    #region 传统作法,无有考虑约束

    /// <summary>

    /// 针对美国人的订单

    /// </summary>

    class OrderUSA

    {

        public void Insert(Order order) { }

    }

    /// <summary>

    /// 什对日本人的订单

    /// </summary>

    class OrderJPN

    {

        public void Insert(Order order) { }

    }

    class OrderService

    {

        OrderUSA orderAction1 = new OrderUSA();

        public void Insert(Order order)

        {

            orderAction1.Insert(order);

        }

    }

    #endregion

 

    #region 解除具体依赖后的程序

    /// <summary>

    /// 和订单操作相关的接口

    /// </summary>

    public interface IOrderAction

    {

        void Insert(Order order);

        void Delete(Order order);

    }

    /// <summary>

    /// 针对中国人的订单

    /// </summary>

    public class OrderChina : IOrderAction

    {

        public void Insert(Order order)

        {

            throw new NotImplementedException();

        }

        public void Delete(Order order)

        {

            throw new NotImplementedException();

        }

    }

    public class OrderService2

    {

        private IOrderAction iOrderInsert;

        /// <summary>

        /// 根据所传递的接口类型的参数来确定使用哪种对象

        /// </summary>

        /// <param name="_iOrderInsert"></param>

        public OrderService2(IOrderAction _iOrderInsert)

        {

            this.iOrderInsert = _iOrderInsert;

        }

        public void InsertOrder(Order order)

        {

            this.iOrderInsert.Insert(order);

        }

        public void DeleteOrder(Order order)

        {

            this.iOrderInsert.Delete(order);

        }

    }

    #endregion

1.2.1 依赖关系图

近些日子大家来剖判一下,那三层之间的注重关系,很领悟,下边包车型客车得以实现中,DomianLogic需求信赖SqlDataAccess,因为DomainLogic中用到了Product这一实体,而以此实体是概念在DataAccess这一层的。WebUI这一层需求依赖DomainLogic,因为ProductService在这一层,同一时候,还索要正视DataAccess,因为在UI中也利用了Product实体,以后一切体系的借助关系是这么的:

图片 1

三个例证,叁个订单系统,它依据国家有不一致的下单方法,对于低层(DATA层)是平等的,但对此世界层,也叫职业逻辑层,它是不等同的,大概小东瀛下单打5拍,中夏族民共和国人下单不巨惠,笔者也是能够明白的,因为中夏族民共和国重油在对于中国人上是很抠门的,而对此小扶桑则慷慨解囊。相当的少说了,看代码:

1.1.1 数据访问层

要达成货品列表这一成效,首先要编写制定数据访问层,要求统一筹划数据库及表,在SQLServer中执会考察计算局筹的数据库表Product结构如下:

图片 2

表设计好之后,就足以发轫写代码了。在Visual Studio
中,新建三个名叫DataAccessLayer的工程,增多二个ADO.NET Entity Data
Model,此时Visual Studio的向导会自动帮大家调换Product实体和ObjectContext
DB操作上下文。那样大家的 Data Access Layer就写好了。

图片 3

破除依赖便是松耦合,松耦合就决然好呢?当然不是程序的耦合度与内聚度要放在一块儿说,当然,对于世界层来讲,适当的滑坡类与类之间的注重是很有不可缺少的,看上边作者的这段代码

2.1 松耦合的代码

3. 结语

轻率大家就编写出了紧耦合的代码,一时候以为分层了就足以化解这一标题,不过大多的时候,都并未有科学的兑现分层。之所以轻松写出紧耦合的代码有三个原因是因为编制程序语言如故开垦条件允许我们只要必要贰个新的实例对象,就能够运用new关键字来实例化一个。假使大家供给加上信赖,Visual
Studio有个别时候能够活动帮大家增添引用。那使得大家很轻巧就犯错,使用new关键字,就只怕会引进以来;增多引用就能发出依赖性。

调整和减弱new引进的借助及紧耦合最棒的法门是使用构造函数注入信赖这种设计情势:即只要我们供给一个依赖的实例,通过构造函数注入。在第三个部分的落到实处演示了什么针对抽象而不是有血有肉编制程序。

构造函数注入是反转调控的叁个例子,因为我们反转了对借助的调控。不是选取new关键字创制一个实例,而是将这种作为委托给了第三方完结。

仰望本文能够给咱们理解哪些真正完毕三层架构,编写松散耦合,可保险,可测试性的代码提供一些增派。

 

http://stackoverflow.com/questions/1362962/when-not-to-use-ioc-and-di

参考http://www.cnblogs.com/yangecnu/p/Introduce-Dependency-Injection.html

1.2.3 问题

除外上面的各层之间耦合下过强之外,代码中还会有其它主题素材。

  • 领域模型就像都写到了数量访问层中。所以世界模型看起来依赖了数码访问层。在数码访问层中定义了名字为Product的类,那体系应该是属于世界模型层的。
  • 表现层中掺入了调节某些用户是还是不是是会员的逻辑。这种事情逻辑应该是
    业务逻辑层中应该管理的,所以也应有松开世界模型层
  • ProductService因为依附了多少访问层,所以也会借助在web.config
    中布置的数据库连接字符串等音讯。那使得,整个业务逻辑层也亟需借助那一个安插才具寻常运作。
  • 在View中,包涵了太多了函数性功能。他推行了威吓类型调换,字符串格式化等操作,这一个职能应该是在分界面展现得模型中成就。

地点也许是大家当先八分之四写代码时候的完毕,
UI分界面层去重视了数量访问层,一时候偷懒就一向引用了这一层,因为实体定义在其间了。业务逻辑层也是借助数据访问层,直接在事情逻辑之中使用了多少访问层里面包车型大巴实体。那样使得全数系统紧耦合,并且可测试性差。那未来我们看看,怎样修改那样叁个系统,使之达到松散耦合,从而升高可测试性呢?

1.2.2 耦合性深入分析

使用三层协会的最重要指标是分离关怀点,当然还会有贰个原因是可测试性。大家相应将世界模型从数额访问层和突显层中分离出来,这样这两个层的变动才不会传染领域模型。在大的种类中,这一点很要紧,那样工夫将系统中的区别部分隔断开来。

最近来看后边的完毕中,有没有模块性,有未有十一分模块能够凝集出来呢。未来丰富多少个新的case来看,系统是不是能够响应那么些须要:

增添新的用户分界面

除此而外WebForm用户之外,恐怕还索要四个WinForm的分界面,以后我们可不可以复用领域层和数量访问层呢?从信赖图中能够见见,未有此外三个模块会凭仗表现层,因而很轻便完成那点退换。我们只要求创立一个WPF的富客户端就可以。今后整个系统的正视性图如下:

图片 4

改造新的数据源

大概过了一段时间,须要把全部连串布局到云上,要动用其余的多寡存款和储蓄技巧,比方Azure
Table Storage Service。现在,整个访问数据的协议发生了变化,访问Azure
Table Storage Service的措施是Http协议,而从前的大多数.NET
访问数据的艺术都以依附ADO.NET
的不二法门。并且数据源的保存方法也时有产生了退换,从前是关系型数据库,以往改为了key-value型数据库。

图片 5 

由地点的依赖关系图能够看出,全体的层都重视了数码访问层,假诺改造数据访问层,则领域逻辑层,和呈现层都亟待张开相应的修改。

1.1.3 表现层

到现在兑现表现层逻辑,这里运用ASP.NET MVC,在Index
页面包车型大巴Controller中,获取商品列表然后将数据重临给View。

public ViewResult Index()
{
    bool isPreferredCustomer = 
        this.User.IsInRole("PreferredCustomer");

    var service = new ProductService();
    var products = 
        service.GetFeaturedProducts(isPreferredCustomer);
    this.ViewData["Products"] = products;

    return this.View();
}

然后在View上校Controller中回到的数量表现出来:

<h2>Featured Products</h2>
<div>
<% var products =
        (IEnumerable<Product>)this.ViewData["Products"];
    foreach (var product in products)
    { %>
    <div>
    <%= this.Html.Encode(product.Name) %>
    (<%= this.Html.Encode(product.UnitPrice.ToString("C")) %>)
    </div>
<% } %>
</div>

2.2 分析

1.1.2 业务逻辑层

显示层实际上能够直接待上访问数据访问层,通过ObjectContext 获取Product
列表。然而超越二分之一景观下,大家不是直接把DB里面包车型地铁数码显现出来,而是须要对数据开展管理,举例对会员,要求对有些商品的价格巨惠。那样我们就必要专门的工作逻辑层,来管理这么些与具体育赛工作逻辑相关的政工。

新建贰个类库,命名为DomainLogic,然后增加一个名字为ProductService的类:

public class ProductService {
    private readonly CommerceObjectContext objectContext;

    public ProductService()
    {
        this.objectContext = new CommerceObjectContext();
    }

    public IEnumerable<Product> GetFeaturedProducts(
        bool isCustomerPreferred)
    {
        var discount = isCustomerPreferred ? .95m : 1;
        var products = (from p in this.objectContext
                            .Products
                        where p.IsFeatured
                        select p).AsEnumerable();
        return from p in products
                select new Product
                {
                    ProductId = p.ProductId,
                    Name = p.Name,
                    Description = p.Description,
                    IsFeatured = p.IsFeatured,
                    UnitPrice = p.UnitPrice * discount
                };
    }
}

当今大家的工作逻辑层已经达成了。

浅谈正视注入

 

多年来几天在看一本名称叫Dependency Injection in
.NET
 的书,重要讲了何等是依附注入,使用注重注入的亮点,以及.NET平台上信赖注入的各个框架和用法。在那本书的始发,讲述了软件工程中的贰个至关心爱戴要的观点正是关切分离(Separation
of
concern, SoC)。依赖注入不是目标,它是一多种工具和花招,最后的目的是赞助大家付出出松散耦合(loose
coupled
)、可体贴、可测试的代码和顺序。那条原则的做法是豪门熟悉的面向接口,也许说是面向抽象编制程序。

关于怎么样是重视注入,在Stack
Overflow上边有三个标题,怎么样向三个5岁的小儿解释重视注入,在那之中得分最高的四个答案是:

“When you go and get things out of the refrigerator for yourself, you
can cause problems. You might leave the door open, you might get
something Mommy or Daddy doesn’t want you to have. You might even be
looking for something we don’t even have or which has expired.

What you should be doing is stating a need, “I need something to drink
with lunch,” and then we will make sure you have something when you sit
down to eat.”

照耀到面向对象程序开荒中就是:高层类(5岁娃儿)应该依据底层基础设备(家长)来提供必需的劳动。

编写松耦合的代码聊到来很简单,但是实际写着写着就产生了紧耦合。

使用例子来注明恐怕越来越精简,首先来看望哪些的代码是紧耦合。

  总之,两个中心的怀念就是,对于二个大类型来讲,把具有的模块尽也许的多分几个,四个之中的事物太多的话,多分开多少个写,一句话表明:高内聚,低耦合

  当整个项目特别庞大,各类艺术之间的调用特别复杂,那么,可以想象一下,如若说未有其它的分开模块的主见,各样关系极其的头眼昏花,不便于维护以及查找bug等等。那一年,就须要一个事物,去将那样多复杂的实物分离开来,很喜爱的一句话:高内聚,低耦合。

2 较好的兑现

凭仗注入能够较好的消除地方出现的难点,现在得以采纳这一合计来又一次完成前边的系统。之所以重新达成是因为,前边的兑现在一方始的就好像就从不设想到扩展性和松耦合,使用重构的不二等秘书籍很难达到规定的标准理想的效益。对于小的系统的话只怕还足以,可是对于叁个巨型的连串,应该是比较费劲的。

在写代码的时候,要保管好依据,在后面包车型大巴贯彻这种,代码直接调整了依赖:当ProductService须要一个ObjectContext类的就如,直接new了三个,当HomeController须要多个ProductService的时候,直接new了一个,那样看起来很酷很方便,实际上使得全体系统具备非常大的局限性,变得紧耦合。new
操作实际就引进了借助,
调节反转这种思量就是要使的大家相比好的管理信赖。

 

2.2.2 时序图

全体体系的时序图如下:

图片 6

系统运维的时候,在Global.asax中开创了八个自定义了Controller工厂类,应用程序将其保存在地点便三种,当页面央求进入的时候,程序出发该工厂类的CreateController方法,并招来web.config中的数据库连接字符串,将其传递给新的SqlProductRepository实例,然后将SqlProductRepository实例注入到HomeControll中,并回到。

下一场使用调用HomeController的实例方法Index来创立新的ProductService类,并通过构造函数字传送入SqlProductRepository。ProductService的GetFeaturedProducts
方法代理给SqlProductRepository实例去达成。

终极,重回填充好了FeaturedProductViewModel的ViewResult对象给页面,然后MVC举行适宜的表现。

2.2.1 依赖关系图

今日,整个种类的注重关系图如下:

图片 7

表现层和数目访问层都信赖领域模型层,那样,在前面包车型客车case中,假使大家新扩展多少个UI界面;改换一种数据源的积攒和收获方式,只要求修改对应层的代码就能够,领域模型层保持了安居。

  从前平昔不明白信赖注入有啥样收益,以至感到它是鸡肋,今后考虑,当时就是可笑。

1.2 分析

前天,遵照三层“架构”大家的代码写好了,并且也达成了必要。整个项目标协会如下图:

 图片 8

那应该是大家不以为奇平日写的所谓的三层架构。在Visual
Studio中,三层之间的信赖能够通过项目引用表现出来。

2.1.1 表现层

首先从展现层来剖析,表现层重大是用来对数码举办展现,不该包蕴过多的逻辑。在Index的View页面中,代码希望得以写成那样

<h2>
    Featured Products</h2>
<div>
    <% foreach (var product in this.Model.Products)
        { %>
    <div>
        <%= this.Html.Encode(product.SummaryText) %></div>
    <% } %>
</div>

能够见见,跟从前的显现层代码相比较,要清洁好些个。很显著是无需开始展览类型调换,要贯彻如此的指标,只须要让Index.aspx这一个视图承继自
System.Web.Mvc.ViewPage<FeaturedProductsViewModel>
就可以,当大家在从Controller创制View的时候,能够展开抉择,然后会自动生成。整个用于呈现的新闻放在了SummaryText字段中。

此地就引进了三个视图模型(View-Specific
Models),他封装了视图的行为,这么些模型只是简短的POCOs对象(Plain Old CLR
Objects)。FeatureProductsViewModel中包蕴了叁个List列表,每一种成分是二个ProductViewModel类,在那之中定义了有个别简约的用来数据展现的字段。

图片 9

方今在Controller中,大家只要求给View重返FeatureProductsViewModel对象就能够。举个例子:

public ViewResult Index()
{
    var vm = new FeaturedProductsViewModel();
    return View(vm);
}

今天回到的是空驶列车表,具体的填写格局在圈子模型中,我们随后看领域模型层。

1.1 紧耦合的代码

有诸多种格局来设计一个灵活的,可拥戴的复杂应用,不过n层架构是一种我们比较熟谙的不二等秘书诀,那当中的挑战在于怎样科学的兑现n层架构。

万一要促成二个非常的粗略的电子商务网址,要列出商品列表,如下:

图片 10

上面就实际来演示经常的做法,是哪些一步一步把代码写出紧耦合的。

 

  举个栗子,现在三个很简短的职能,可能只需求通过某个主意相互调用就足以兑现,OK,那么随着供给的加码,今后加上了多少个职能,那么,大家把同样的东西划分为一个类吧,类经过而生,同样,类似的,一层一层如下所示:

 

2.1.2 领域逻辑层

新建三个类库,这其间富含POCOs和一部分华而不实类型。POCOs用来对领域建立模型,抽象类型提供抽象作为达到世界模型的进口。重视注入的标准是面向接口而不是切实的类编制程序,使得我们得以轮换具体达成。

今昔我们必要为展现层提供数据。由此用户分界面层须求引用领域模型层。对数据访问层的简练抽象能够采取Patterns
of Enterprise Application
Architecture一书中讲到的Repository格局。因而定义叁个ProductRepository抽象类,注意是抽象类,在天地模型库中。它定义了贰个到手具有特价商品的画饼充饥方法:

public abstract class ProductRepository
{
    public abstract IEnumerable<Product> GetFeaturedProducts();
}

以此办法的Product类中只定义了商品的中央消息举个例子名称和单价。整个涉及图如下:

图片 11

现行反革命来看表现层,HomeController中的Index方法应该要采纳ProductService实例类来博取商品列表,施行价格减价,并且把Product类似转化为ProductViewModel实例,并将该实例到场到FeaturesProductsViewModel中。因为ProductService有三个含有类型为ProductReposity抽象类的构造函数,所以那边能够因此构造函数注入完结了ProductReposity抽象类的实例。这里和事先的最大差距是,大家尚无应用new关键字来及时new三个目的,而是通过构造函数的秘技传入具体的贯彻。

这几天来看表现层代码:

public partial class HomeController : Controller
{
    private readonly ProductRepository repository;

    public HomeController(ProductRepository repository)
    {
        if (repository == null)
        {
            throw new ArgumentNullException("repository");
        }

        this.repository = repository;
    }

    public ViewResult Index()
    {
        var productService = new ProductService(this.repository);

        var vm = new FeaturedProductsViewModel();

        var products = productService.GetFeaturedProducts(this.User);
        foreach (var product in products)
        {
            var productVM = new ProductViewModel(product);
            vm.Products.Add(productVM);
        }

        return View(vm);
    }

}

在HomeController的构造函数中,传入了落成了ProductRepository抽象类的二个实例,然后将该实例保存在概念的私有的只读的ProductRepository类型的repository对象中,这就是独立的通过构造函数注入。在Index方法中,获取数据的ProductService类中的重要功用,实际上是由此传播的repository类来代劳完结的。

ProductService类是贰个彻彻底底的小圈子对象,完结如下:

public class ProductService
{
    private readonly ProductRepository repository;

    public ProductService(ProductRepository repository)
    {
        if (repository == null)
        {
            throw new ArgumentNullException("repository");
        }

        this.repository = repository;
    }

    public IEnumerable<DiscountedProduct> GetFeaturedProducts(IPrincipal user)
    {
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }

        return from p in
                        this.repository.GetFeaturedProducts()
                select p.ApplyDiscountFor(user);
    }
}

可以看出ProductService也是因而构造函数注入的艺术,保存了落到实处了ProductReposity抽象类的实例,然后借助该实例中的GetFeatureProducts方法,获取原始列表数据,然后开展打折管理,进而完成了协调的GetFeaturedProducts方法。在该GetFeaturedProducts方法中,跟从前分裂的地方在于,今后的参数是IPrincipal,而不是事先的bool型,因为判别用户的现象,那是一个作业逻辑,不应有在展现层管理。IPrincipal是BCL中的类型,所以不设有额外的依靠。大家应该依照接口编制程序IPrincipal是应用程序用户的一种标准方法。

此地将IPrincipal作为参数字传送递给有些方法,然后再里面调用实现的点子是依赖注入中的方法注入的花招。和构造函数注入一样,同样是将中间贯彻代理给了传播的信赖对象。

今昔大家只剩余两块地点未有拍卖了:

  • 未曾ProductRepository的求实实现,那一个很轻巧实现,前面停放数据访问层里面去管理,大家只必要创建叁个实际的实现了ProductRepository的数额访问类就可以。
  • 私下认可上,ASP.NET MVC
    希望Controller对象有投机的私下认可构造函数,因为大家在HomeController中增多了新的构造函数来注入依赖,所以MVC框架不知道如何缓慢解决创设实例,因为有依据。那么些主题素材得以透过付出一个IControllerFactory来消除,该对象足以创造三个切实可行的ProductRepositry实例,然后传给HomeController这里非常的少讲。

今天大家的领域逻辑层已经写好了。在该层,大家只操作领域模型对象,以及.NET
BCL
中的基本对象。模型使用POCOs来代表,命名叫Product。领域模型层必须能够和外围举办沟通(database),所以需求一个抽象类(Repository)来时做到这一功力,并且在须求的时候,能够轮换具体完成。

2.1.3 数据访问层

方今我们得以选取LINQ to
Entity来落到实处具体的数量访问层逻辑了。因为要落实世界模型的ProductRepository抽象类,所以要求引进世界模型层。注意,这里的依据产生了数量访问层正视领域模型层。跟以前的恰好相反,代码达成如下:

public class SqlProductRepository : Domain.ProductRepository
{
    private readonly CommerceObjectContext context;

    public SqlProductRepository(string connString)
    {
        this.context =
            new CommerceObjectContext(connString);
    }

    public override IEnumerable<Domain.Product> GetFeaturedProducts()
    {
        var products = (from p in this.context.Products
                        where p.IsFeatured
                        select p).AsEnumerable();
        return from p in products
                select p.ToDomainProduct();
    }
}

在此地供给留意的是,在圈子模型层中,大家定义了二个名称叫Product的天地模型,然后再数据访问层中Entity
Framework帮我们也生成了叁个名叫Product的多寡访问层实体,他是和db中的Product表相继对应的。所以大家在措施重返的时候,需求把项目从db中的Product调换为世界模型中的POCOs
Product对象。

图片 12 

Domain
Model中的Product是二个POCOs类型的靶子,他只是包涵领域模型中供给使用的一对着力字段,DataAccess中的Product对象是光彩夺目到DB中的实体,它蕴涵数据库中Product表定义的有所字段,在数额表现层中我们定义了三个ProductViewModel数据表现的Model。

这三个目的之间的调换很粗大略:

public class Product
{
    public Domain.Product ToDomainProduct()
    {
        Domain.Product p = new Domain.Product();
        p.Name = this.Name;
        p.UnitPrice = this.UnitPrice;
        return p;
    }
}

艺术–>类–>接口–>模块–>以致把各样模块之间的关系抽象出来(比方IOC/DI)

2.2.3 新的构造

在1.1的达成中,选用了三层架构,在改良后的兑现中,在UI层和天地模型层中进入了三个人作品突显模型(presentation
model)层。如下图:

图片 13

 

将Controllers和ViewModel从表现层移到了展现模型层,仅仅将视图(.aspx和.ascx文件)和聚合根对象(Composition
Root)保留在了表现层中。之所以这么管理,是足以使得尽恐怕的驱动表现层能够可铺排而别的部分尽恐怕的可以维持不改变。

1 不佳的达成

编写松耦合代码的率先步,也许我们都耳濡目染,这就是对系统一分配层。举个例子上边包车型大巴经文的三层架构。

图片 14

分完层和贯彻好是两件工作,并不是说分好层之后就可见松耦合了。

  那个主见正似乎说接口是从未有过用处同样。