MEF实现设计上的“松耦合”

C#进阶系列——MEF实现设计上的“松耦合”(二)

前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识。当然MEF的用法可能不限于此,比如MEF的目录服务、目录筛选、重组部件等高级应用在这里就不做过多讲解,因为博主觉得这些用法只有在某些特定的环境下面才会用到,着实不太普遍,感觉没有钻下去的必要。如果你有兴趣也可以去了解下。这篇打算将MEF和仓储模式结合起来谈谈MEF在项目中的使用。

1、仓储模式:也叫Repository模式。Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。Repository模式一般是用来封装数据访问层的,这也就是为什么很多地方看到说的什么“数据仓储”,大概就是这个意思。Repository模式并不是本文的重点,这里就不再展开,后面会单独分享这块。

关于仓储模式有以下几点需要注意:

(1)Repository模式是架构模式,在设计架构时,才有参考价值;

(2)Repository模式使用的意义:一是隔离业务逻辑层和底层数据访问层,保证数据出入口的唯一性;二是Repository模式针对聚合根设计的,而并不是针对表和实体设计的,换句话说,使用Repository是为了实现内聚,前端只负责向Repository请求数据即可,而不用关心数据的具体来源;

(3)Repository模式实际用途:更换、升级ORM引擎,不影响业务逻辑;

上面这些东西写得有点官方。博主的理解是,仓储模式就是对数据访问层(或者叫数据映射层)做了一层包装,每一次前端需要查询什么数据或者提交什么数据的时候,都是通过仓储对象Repository去操作的,前端基本上感觉不到数据访问层的存在。这样说你有没有好理解一点呢?没有?好吧,我们来看Demo。

2、MEF在仓储模式上面的应用:由于框架使用的是EF,所以这里也用EF结合仓储模式进行讲解。为了省略Repository模式的复杂结构,我们仅仅通过仓储的Save方法来说明。

IRepository<TEntity>接口以及实现代码:

  public interface IRepository<T>
     where T : BaseEntity
    {
        T Save(T entitiy);
    }

  [Export(typeof(IRepository<BaseEntity>))]
    public abstract class Repository<T> : IRepository<T> where T : BaseEntity
    {
        //工作单元
        [Import]
        protected IUnitOfWork context { set; get; }

        private IDbSet<T> _entities;

        //注册MEF
        public Repository()
        {
            Register.regisgter().ComposeParts(this);
        }

        public virtual T Save(T entitiy)
        {
            if (entitiy == null) throw new ArgumentException("entitiy nul");
            context.Save<T>(entitiy);
            return entitiy;
        }
    }

    public static class Register
    {
        public static CompositionContainer regisgter()
        {
            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var container = new CompositionContainer(catalog);
            return container;
        }
    }

BaseEntity是一个EF实体的公共基类,定义EF实体必须要遵循的约束。

IUnitOfWork工作单元接口以及实现

  public interface IUnitOfWork : IDisposable
    {
        int Commit();

        void Rollback();

        void Save<T>(T entity) where T : BaseEntity;
    }

     /// <summary>
        /// 单元操作实现
        /// </summary>     [Export(typeof(IUnitOfWork))]
        public abstract class UnitOfWorkContextBase : IUnitOfWork
        {
            [ImportMany]
            protected abstract IEnumerable<DbContext> Contexts { get; }
            protected abstract DbContext Cur_context { get; set; }

            public UnitOfWorkContextBase()
            {          Register.regisgter().ComposeParts(this);
                if (Contexts.Count() <= 0)
                {
                    throw new Exception();
                }
                Cur_context = Contexts.FirstOrDefault();
            }

            /// <summary>
            ///     获取 当前单元操作是否已被提交
            /// </summary>
            public bool IsCommitted { get; private set; }

            /// <summary>
            ///     提交当前单元操作的结果
            /// </summary>
            /// <returns></returns>
            public int Commit()
            {
                if (IsCommitted)
                {
                    return 0;
                }
                try
                {
                    int result = Cur_context.SaveChanges();
                    IsCommitted = true;
                    return result;
                }
                catch (DbUpdateException e)
                {
                    if (e.InnerException != null && e.InnerException.InnerException is SqlException)
                    {
                        SqlException sqlEx = e.InnerException.InnerException as SqlException;
                        string msg = DataHelper.GetSqlExceptionMessage(sqlEx.Number);
                        throw PublicHelper.ThrowDataAccessException("提交数据更新时发生异常:" + msg, sqlEx);
                    }
                    throw;
                }
            }

            /// <summary>
            /// 把当前单元操作回滚成未提交状态
            /// </summary>
            public void Rollback()
            {
                IsCommitted = false;
            }

            public void Dispose()
            {
                if (!IsCommitted)
                {
                    Commit();
                }
                Cur_context.Dispose();
            }

            public void Save<T>(T entity) where T : T
            {
                Cur_context.SaveChanges();
            }
        }

既然这里使用了ImportMany,那么肯定有一个地方需要Export。我们使用EF新建一个edmx文件,在生成的上下文对象上面加上Export

  [Export(typeof(DbContext))]
    public partial class Entities : DbContext
    {
        public Entities()
            : base("name=Entities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<TB_USERS> TB_USERS { get; set; }
    }

这里为什么要使用ImportMany?前面说了,仓储的好处之一在于对数据访问层做封装,使得前端不比关心数据的具体来源。当我们再建一个数据库连接的edmx时,我们只需要修改仓储里面的Cur_context 这个对象的赋值即可,由于其他地方都是针对Cur_context这一个上下文对象做的操作,所以基本都不需要做很大的变化。绕了这么大一圈,其实博主只是想说明Import和ImportMany和仓储模式结合使用的好处,至于仓储模式的适用性问题不是本文的重点。

时间: 2024-10-10 11:16:44

MEF实现设计上的“松耦合”的相关文章

C#进阶系列——MEF实现设计上的“松耦合”(四):构造函数注入

前言:今天十一长假的第一天,本因出去走走,奈何博主最大的乐趣是假期坐在电脑前看各处堵车,顺便写写博客,有点收获也是好的.关于MEF的知识,之前已经分享过三篇,为什么有今天这篇?是因为昨天分享领域服务的时候,用到MEF的注入有参构造函数的方法,博主好奇心重,打算稍微深挖一下,这篇来对此知识点做个总结. 还是将前面三篇的目录列出来,对MEF没有了解的朋友,可以先看看: C#进阶系列——MEF实现设计上的“松耦合”(一) C#进阶系列——MEF实现设计上的“松耦合”(二) C#进阶系列——MEF实现设

C#进阶系列——MEF实现设计上的“松耦合”(二)

前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级应用在这里就不做过多讲解,因为博主觉得这些用法只有在某些特定的环境下面才会用到,着实不太普遍,感觉没有钻下去的必要.如果你有兴趣也可以去了解下.这篇打算将MEF和仓储模式结合起来谈谈MEF在项目中的使用. 1.仓储模式:也叫Repository模式.Repository是一个独立的层,介于领域层与数

MEF实现设计上的“松耦合”(一)

1.什么是MEF 先来看msdn上面的解释:MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置. 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项. 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展. 也有人把MEF解释为“依赖注入”的一种方式,那么什么是“依赖注入”?如果这样解释,感觉越陷越深......根据博主的理解,了解MEF只需要

C#进阶系列——MEF实现设计上的“松耦合”(一)

前言:最近去了趟外地出差,介绍推广小组开发的框架类产品.推广对象是本部门在项目上面的同事——1到2年工作经验的初级程序员.在给他们介绍框架时发现很多框架设计层面的知识他们都没有接触过,甚至没听说过,这下囧了~~于是乎在想该如何跟他们解释MEF.AOP.仓储模式等方面的东东.本来 C#基础系列 应该还有两篇关于异步的没有写完,奈何现在要推广这些个东西,博主打算先介绍下项目中目前用到的些技术,异步的往后有时间再做分享.C#进阶系列主要围绕MEF.AOP.仓储模式.Automapper.WCF等展开.

MEF实现设计上的“松耦合”(三)

1.面向接口编程:有一定编程经验的博友应该都熟悉或者了解这种编程思想,层和层之间通过接口依赖,下层不是直接给上层提供服务,而是定义一组接口供上层调用.至于具体的业务实现,那是开发中需要做的事情,在项目架构阶段,只需要定义好层与层之间的接口依赖,将框架搭起来,编译可以直接通过.为什么要有这么一种设计?既然是架构设计,当然是为了提高架构的灵活性,降低层和层之间的依赖(耦合).这个并非一句两句讲得清楚的,更多详细可以参看:面向接口编程详解(一)——思想基础.此文我觉得分析比较到位.好了,不说废话,来看

MEF实现设计上的“松耦合”(二)

介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级应用在这里就不做过多讲解,因为博主觉得这些用法只有在某些特定的环境下面才会用到,着实不太普遍,感觉没有钻下去的必要.如果你有兴趣也可以去了解下.这篇打算将MEF和仓储模式结合起来谈谈MEF在项目中的使用. 1.仓储模式:也叫Repository模式.Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间.它的存在让领域层感觉不到数据访问层的

Prism 4 文档 ---第9章 松耦合组件之间通信

当构建一个大而负责的应用程序时,通用的做法时将功能拆分到离散的模块程序集中.将模块之间的静态引用最小化.这使得模块可以被独立的开发,测试,部署和升级,以及它迫使松散耦合的沟通. 当在模块之间通信时,你需要知道不同通信方式之间的区别,那样你才能确定哪种方式对于你的特定的场景最合适,Prism类库提供了以下几种通信方式: 命令.当希望对于用户的交互马上采取动作时使用. 事件聚合.用于ViewModel,展现层,或者控制之间没有所期望的直接动作时. 区域上下文.使用它可以提供宿主和宿主区域的View之

松耦合和紧耦合

Question:首先,明确一点,什么是松耦合?什么是紧耦合? Answer:比如说两个模块,A模块和B模块,当两者的关联非常多的时候,就叫紧耦合,反之,则是松耦合. 实现松耦合的方式有,使用接口抽象出来,当两个模块的关联仅仅是根据几个接口就可以实现的话,那么,就应当叫松耦合,实现松耦合是非常有必要的. By the way,在软件设计中,应该把层次尽量分开,多分几层,每一层各尽其职,高内聚,低耦合,同时,可以将两个模块的关系也抽象出来,比如说IOC/DI的设计模式,有人说spring的IOC/

Spring松耦合示例(转)

Spring松耦合示例 面向对象设计的理念是把整个系统分成一组可重用的组件,然而,当系统变得越大的时候,尤其是在java中,这最大的对象依赖将会紧紧耦合,以至于非常难以管理和修改,而现在,你可以使用Spring框架扮演一个中间模块的角色,方便高效地管理其他组件依赖 输出生成的例子 看个例子,假设你的项目有一个方法可以输出内容到csv或者json格式,你可能写出这样的代码 package com.mkyong.output; public interface IOutputGenerator {