基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现

我们设计的分层架构,层与层之间应该是松散耦合的。因为是单向单一调用,所以,这里的“松散耦合”实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口。这样,上层类不能直接实例化下层中的类,而只持有接口,至于接口所指变量最终究竟是哪一个类,则由依赖注入机制决定。

之所以这样做,是为了实现层与层之间的“可替换”式设计,例如,现在需要换一种方式实现数据访问层,只要这个实现遵循了前面定义的数据访问层接口,业务逻辑层和表示层不需要做任何改动,只需要改一下配置文件系统即可正常运行。另外,基于这种结构的系统,还可以实现并行开发。即不同开发人员可以专注于自己的层次,只有接口被定义好了,开发出来的东西就可以无缝连接。

在J2EE平台上,主要使用Spring框架实现依赖注入。这里,我们将自己做一个依赖注入容器。

依赖注入的理论基础是Abstract Factory设计模式,这里结合具体实例简单介绍一下。

图6.1、Abtract Factory应用示例
 

上图以数据访问层为例,展示了Abstract Factory模式的应用。如图,现假设有针对Access和SQLServer两种数据库的数据访问层,它们都实现了数据访问层接口。每个数据访问层有自己的工厂,所有工厂都实现自IDALFactory接口。而客户类(这里就是业务逻辑层类)仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样,只要通过配置文件确定实例化哪个工厂,就可以得到不同的数据访问层。
 
然而,这种设计虽然可行,但是代码比较冗余,因为这样需要为数据访问层的每一个实现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但是,.NET平台引入的反射机制,给我们提供了一种解决方案。使用反射,每个层只需要一个工厂,然后通过从配置文件中读出程序集的名称,动态加载相应类。另外,为了提高依赖注入机制的效率,这里引入缓存机制。下面来看具体实现。

配置
首先,需要在Web工程的Web.config文件的<appSettings>节点下添加如下两个项:
<add key="DAL" value=""/>
<add key="BLL" value=""/>
这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value目前是空,是因为目前还没有各个层次的具体实现。

实现缓存操作辅助类
为实现缓存操作,我们将缓存操作封装成一个辅助类,放在Utility工程下,具体代码如下:

CacheAccess.cs:

using System;
using System.Web;
using System.Web.Caching;

namespace NGuestBook.Utility
{
    
/// <summary>
    
/// 辅助类,用于缓存操作
    
/// </summary>
    public sealed class CacheAccess
    {
        
/// <summary>
        
/// 将对象加入到缓存中
        
/// </summary>
        
/// <param name="cacheKey">缓存键</param>
        
/// <param name="cacheObject">缓存对象</param>
        
/// <param name="dependency">缓存依赖项</param>
        public static void SaveToCache(string cacheKey, object cacheObject, CacheDependency dependency)
        {
            Cache cache 
= HttpRuntime.Cache;
            cache.Insert(cacheKey, cacheObject, dependency);
        }

        
/// <summary>
        
/// 从缓存中取得对象,不存在则返回null
        
/// </summary>
        
/// <param name="cacheKey">缓存键</param>
        
/// <returns>获取的缓存对象</returns>
        public static object GetFromCache(string cacheKey)
        {
            Cache cache 
= HttpRuntime.Cache;

            
return cache[cacheKey];
        }
    }
}


封装依赖注入代码
因为很多依赖注入代码非常相似,为了减少重复性代码,我们将可复用的代码先封装在一个类中。具体代码如下(这个类放在Factory工程下):

DependencyInjector.cs:

using System;
using System.Configuration;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using NGuestBook.Utility;

namespace NGuestBook.Factory
{
    
/// <summary>
    
/// 依赖注入提供者
    
/// 使用反射机制实现
    
/// </summary>
    public sealed class DependencyInjector
    {
        
/// <summary>
        
/// 取得数据访问层对象
        
/// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
        
/// </summary>
        
/// <param name="className">数据访问类名称</param>
        
/// <returns>数据访问层对象</returns>
        public static object GetDALObject(string className)
        {
            
/// <summary>
            
/// 取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取
            
/// 缓存依赖项为Web.Config文件
            
/// </summary>
            object dal = CacheAccess.GetFromCache("DAL");
            
if (dal == null)
            {
                CacheDependency fileDependency 
= new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
                dal 
= ConfigurationManager.AppSettings["DAL"];
                CacheAccess.SaveToCache(
"DAL", dal, fileDependency);
            }

            
/// <summary>
            
/// 取得数据访问层对象
            
/// </summary>
            string dalName = (string)dal;
            
string fullClassName = dalName + "." + className;
            
object dalObject = CacheAccess.GetFromCache(className);
            
if (dalObject == null)
            {
                CacheDependency fileDependency 
= new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
                dalObject 
= Assembly.Load(dalName).CreateInstance(fullClassName);
                CacheAccess.SaveToCache(className, dalObject, fileDependency);
            }

            
return dalObject;
        }

        
/// <summary>
        
/// 取得业务逻辑层对象
        
/// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
        
/// </summary>
        
/// <param name="className">业务逻辑类名称</param>
        
/// <returns>业务逻辑层对象</returns>
        public static object GetBLLObject(string className)
        {
            
/// <summary>
            
/// 取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取
            
/// 缓存依赖项为Web.Config文件
            
/// </summary>
            object bll = CacheAccess.GetFromCache("BLL");
            
if (bll == null)
            {
                CacheDependency fileDependency 
= new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
                bll 
= ConfigurationManager.AppSettings["BLL"];
                CacheAccess.SaveToCache(
"BLL", bll, fileDependency);
            }

            
/// <summary>
            
/// 取得业务逻辑层对象
            
/// </summary>
            string bllName = (string)bll;
            
string fullClassName = bllName + "." + className;
            
object bllObject = CacheAccess.GetFromCache(className);
            
if (bllObject == null)
            {
                CacheDependency fileDependency 
= new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
                bllObject 
= Assembly.Load(bllName).CreateInstance(fullClassName);
                CacheAccess.SaveToCache(className, bllObject, fileDependency);
            }

            
return bllObject;
        }
    }
}


实现工厂
下面使用两个辅助类,实现数据访问层工厂和业务逻辑层工厂。

DALFactory.cs

using System;
using NGuestBook.IDAL;

namespace NGuestBook.Factory
{
    
/// <summary>
    
/// 数据访问层工厂,用于获取相应的数据访问层对象
    
/// 使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计
    
/// </summary>
    public sealed class DALFactory
    {
        
/// <summary>
        
/// 获取管理员数据访问层对象
        
/// </summary>
        
/// <returns>管理员数据访问层对象</returns>
        public static IAdminDAL CreateAdminDAL()
        {
            
return (IAdminDAL)DependencyInjector.GetDALObject("AdminDAL");
        }

        
/// <summary>
        
/// 获取留言数据访问层对象
        
/// </summary>
        
/// <returns>留言数据访问层对象</returns>
        public static IMessageDAL CreateMessageDAL()
        {
            
return (IMessageDAL)DependencyInjector.GetDALObject("MessageDAL");
        }

        
/// <summary>
        
/// 获取评论数据访问层对象
        
/// </summary>
        
/// <returns>评论数据访问层对象</returns>
        public static ICommentDAL CreateCommentDAL()
        {
            
return (ICommentDAL)DependencyInjector.GetDALObject("CommentDAL");
        }
    }
}


BLLFactory.cs

using System;
using NGuestBook.IBLL;

namespace NGuestBook.Factory
{
    
/**//// <summary>
    
/// 业务逻辑层工厂,用于获取相应的业务逻辑层对象
    
/// 使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计
    
/// </summary>
    public sealed class BLLFactory
    {
        
/**//// <summary>
        
/// 获取管理员业务逻辑层对象
        
/// </summary>
        
/// <returns>管理员业务逻辑层对象</returns>
        public static IAdminBLL CreateAdminBLL()
        {
            
return (IAdminBLL)DependencyInjector.GetBLLObject("AdminBLL");
        }

        
/**//// <summary>
        
/// 获取留言业务逻辑层对象
        
/// </summary>
        
/// <returns>留言业务逻辑层对象</returns>
        public static IMessageBLL CreateMessageBLL()
        {
            
return (IMessageBLL)DependencyInjector.GetBLLObject("MessageBLL");
        }

        
/**//// <summary>
        
/// 获取评论业务逻辑层对象
        
/// </summary>
        
/// <returns>评论业务逻辑层对象</returns>
        public static ICommentBLL CreateCommentBLL()
        {
            
return (ICommentBLL)DependencyInjector.GetBLLObject("CommentBLL");
        }
    }
}

 

作者:T2噬菌体
出处:http://leoo2sk.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

Tag标签: .NET,分层架构
posted @ 2008-06-19 11:36 EricZhang(T2噬菌体) 阅读(6509) 评论(67)  编辑 收藏 网摘 所属分类: .NET

  回复  引用  查看    
#1楼2008-06-19 11:53 | FLYabroad      
不错
  回复  引用    
#2楼2008-06-19 11:58 | WaitdDing[未注册用户]
<add key="BLL" value=""/>
难道业务逻辑也要替换掉?


  回复  引用  查看    
#3楼2008-06-19 11:58 | Ants      
你把实例都缓存起来,,然后每次都 从缓存里取,,那取出的不都是同一个实例吗?
会不会有问题啊?

  回复  引用  查看    
#4楼[楼主]2008-06-19 12:00 | T2噬菌体      
--引用--------------------------------------------------
WaitdDing: &lt;add key=&quot;BLL&quot; value=&quot;&quot;/&gt;
难道业务逻辑也要替换掉?


--------------------------------------------------------
恩,在较复杂的系统中,业务逻辑层也是有可能被替换的。

  回复  引用  查看    
#5楼[楼主]2008-06-19 12:02 | T2噬菌体      
--引用--------------------------------------------------
Ants: 你把实例都缓存起来,,然后每次都 从缓存里取,,那取出的不都是同一个实例吗?
会不会有问题啊?
--------------------------------------------------------

这正是一个优势,因为这里缓存都是操作类,而每个操作类全局只需要一个实例,使用缓存机制,不但提高了效率,还免去了使用Singleton模式。

  回复  引用  查看    
#6楼2008-06-19 12:04 | Ants      
--引用--------------------------------------------------
T2噬菌体: --引用--------------------------------------------------
Ants: 你把实例都缓存起来,,然后每次都 从缓存里取,,那取出的不都是同一个实例吗?
会不会有问题啊?
--------------------------------------------------------

这正是一个优势,因为这里缓存都是操作类,而每个操作类全局只需要一个实例,使用缓存机制,不但提高了效率,还免去了使用Singleton模式。
--------------------------------------------------------
操作类啊。。你又不说明白点。。呵呵~。
不过操作类的话,,你可以直接写成静态的啊,,SQLHelper里面都写成静态的方法

  回复  引用  查看    
#7楼2008-06-19 12:05 | 水言木      
不错
  回复  引用  查看    
#8楼[楼主]2008-06-19 12:05 | T2噬菌体      
@Ants

呵呵,不好意思,下次我会注意写的明白点

我的辅助类都写成静态的了,如CacheAccess这些,但是操作类因为要实现依赖注入,因此需要具有多态性,写成静态就失去多态性了,因此这里还是写成普通类。通过缓存机制,保证全局唯一实例,免去Singleton模式

  回复  引用  查看    
#9楼2008-06-19 12:15 | Yok      
为何不用Windsor?
  回复  引用  查看    
#10楼[楼主]2008-06-19 12:17 | T2噬菌体      
@Yok
……没听说过,请问什么是Windsor啊……

  回复  引用  查看    
#11楼2008-06-19 12:32 | 金色海洋(jyk)      
只有接口被定义好了,开发出来的东西就可以无缝连接。

这个很对哦。我想问的是 您的接口是怎么设计的?

什么时候(阶段、时期),依据什么,是不是需要很丰富的项目经验,

如果接口定义发生了变化,会是什么样子的。

  回复  引用  查看    
#12楼2008-06-19 12:34 | 艺林      
一口气看完楼主这个系列目前发布的文章,感觉这个架构和PetShop4基本一致!
  回复  引用  查看    
#13楼[楼主]2008-06-19 12:50 | T2噬菌体      
@金色海洋(jyk)

确实,接口的设计需要很丰富的项目经验。一般来说,是按这个顺序:首先根据需求分析设计出UI(或者UI原型),然后找出各个UI都需要什么业务逻辑支持,确定业务逻辑接口,然后根据业务逻辑确定出需要何种数据访问操作,确定数据访问层接口。这个过程可能会有迭代。

如果接口需要改变,那下场会相当惨……不过用极限编程思想来说,我们是不是应该“拥抱改变”呢,呵呵

  回复  引用  查看    
#14楼[楼主]2008-06-19 12:54 | T2噬菌体      
--引用--------------------------------------------------
艺林: 一口气看完楼主这个系列目前发布的文章,感觉这个架构和PetShop4基本一致!
--------------------------------------------------------

其实还是有很多不一样的地方。
1.PetShop4的业务逻辑层是和表示层强耦合的,我的解耦了。
2.PetShop4没有将依赖注入相关代码封装,也没有在这里使用缓存。
3.PetShop4用到了很多特性,如MemberShip等,使得整个架构相当复杂,而我的没有,只保留最核心的架构。

如果看后面:
4.PetShop4没有使用ORM实现数据访问层,这里牵涉到一个非常重要的实体类解耦问题。
5.PetShop4的表示层没有引入Ajax元素。

最重要的是,PetShop4可没告诉你它是怎么一步一步做成的。呵呵。

  回复  引用  查看    
#15楼2008-06-19 13:03 | AlexChen      
这个UML图,好凌乱啊,还好以前看过类似的图,不然有点眼晕了哦!:-)
支持博主...
收藏了.

  回复  引用  查看    
#16楼[楼主]2008-06-19 13:16 | T2噬菌体      
@AlexChen

不好意思,StarUML用的还不是很好

  回复  引用  查看    
#17楼2008-06-19 13:28 | 紫色阴影      
设计不合理,没有必要这么复杂,如果真的是有Access和sql server两种需求的话
可以用一个DAL,使用不同的Provider就行了,比如AccessProvider和SqlProvider
如果每个表都有一个DAL与之相对应,那岂不是10个表就有20个类+10个接口?
DAL层过于庞大
而且如果要添加Oracle的话,就得为所有的DAL接口添加一个实现,与之比较起来,添加一个Provider实现更为简洁

  回复  引用  查看    
#18楼[楼主]2008-06-19 13:31 | T2噬菌体      
@紫色阴影

那么如何解决不同数据库间SQL的差异呢,如何解决有些数据库不支持存储过程呢?

如果换用ORM,你的Provider又要又如何应对呢?

如果不用数据库而换用XML作为数据源,你的数据访问层能应对吗?

  回复  引用  查看    
#19楼2008-06-19 13:36 | 紫色阴影      
引入Factory是完全没有必要的,可以利用ioc框架把相应的DAL注入到BLL中去

  回复  引用  查看    
#20楼2008-06-19 13:39 | 紫色阴影      
@T2噬菌体
Privoder就是用来解决数据库可能变化的问题,不管是sql server还是access还是xml或者是内存数据库
如果是sql差异可以引入sqlDialect
这是比较成熟的设计了,你可以参考下Hibernate的实现

  回复  引用  查看    
#21楼[楼主]2008-06-19 13:39 | T2噬菌体      
--引用--------------------------------------------------
紫色阴影: 引入Factory是完全没有必要的,可以利用ioc框架把相应的DAL注入到BLL中去

--------------------------------------------------------
IoC框架本身就是一个Factory

  回复  引用  查看    
#22楼[楼主]2008-06-19 13:41 | T2噬菌体      
@紫色阴影

恩,好的,我会参考一下Hibernate,看看如何改进比较好

  回复  引用  查看    
#23楼2008-06-19 13:45 | 紫色阴影      
举个例子,
UserDAL中的查找:
User FindUserByName(string name)
{
return provider.Find<User>(UserFields.Name == name);
}

//或者provider.Find<User>("Name=" + name);
不管你是什么数据库什么查询,都交给provider来做就好了


  回复  引用  查看    
#24楼2008-06-19 13:46 | 紫色阴影      

--引用--------------------------------------------------
T2噬菌体: --引用--------------------------------------------------
紫色阴影: 引入Factory是完全没有必要的,可以利用ioc框架把相应的DAL注入到BLL中去

--------------------------------------------------------
IoC框架本身就是一个Factory

--------------------------------------------------------
Sorry,没有说清楚,我的意思是引入DALFactory没有必要

  回复  引用  查看    
#25楼2008-06-19 13:47 | 紫色阴影      
这是我昨天写的关于数据库访问层的想法,http://www.cnblogs.com/blusehuang/archive/2008/06/19/1225096.html
有时间可以讨论

  回复  引用  查看    
#26楼2008-06-19 13:49 | Meazza-mFrog      
可以把内容写的更详细点

  回复  引用  查看    
#27楼[楼主]2008-06-19 13:53 | T2噬菌体      
--引用--------------------------------------------------
紫色阴影: 举个例子,
UserDAL中的查找:
User FindUserByName(string name)
{
return provider.Find&lt;User&gt;(UserFields.Name == name);
}

//或者provider.Find&lt;User&gt;(&quot;Name=&quot; + name);
不管你是什么数据库什么查询,都交给provider来做就好了


--------------------------------------------------------

这个实现方法和NBear的ORM很相似……
如果这个provider能良好的支持所有的数据库和数据源,那当然是很好,可是不同数据库间差异太大……而且,这样会令控制粒度变粗

当然,这是一对对立统一的矛盾,即减少的代码量就降低了控制精度和可扩展性,提高了控制精度和可扩展性必然使代码增加。应该辩证来看:如果系统所用到的数据源都是常用数据库,使用provider是很好的;但如果数据源变动性很大,还是最好写单独的数据访问层。

  回复  引用  查看    
#28楼2008-06-19 14:01 | henry      
现在这么多IOC组件都不用,可对对象生命周管理等一系列功能.
Yok说的是castle的ioc功能.

  回复  引用  查看    
#29楼[楼主]2008-06-19 14:04 | T2噬菌体      
@henry

哦,我对这个组件一点也不了解,这是第一次听说,有时间一定会要学习一下。

  回复  引用    
#30楼2008-06-19 14:08 | 手机魔卡[未注册用户]
学了不少东西,谢谢
  回复  引用  查看    
#31楼2008-06-19 14:27 | 紫色阴影      
@henry
是啊 spring.net, castle, unity很多选择

  回复  引用  查看    
#32楼2008-06-19 14:29 | 紫色阴影      
@T2噬菌体
自己是做不过来的,所以为什么不把这种变化交给Hibernate这样的持久层框架去做,而要自己实现呢
企业级开发关注的是业务,解决企业的问题,而不是技术层面上的东西。有现有优秀的框架就去用吧
NBear听说很好,可惜一直没有尝试过

  回复  引用  查看    
#33楼2008-06-19 14:32 | 紫色阴影      
--引用--------------------------------------------------
当然,这是一对对立统一的矛盾,即减少的代码量就降低了控制精度和可扩展性,提高了控制精度和可扩展性必然使代码增加。应该辩证来看:如果系统所用到的数据源都是常用数据库,使用provider是很好的;但如果数据源变动性很大,还是最好写单独的数据访问层。
--------------------------------------------------------
如果有了100个DAL类,突然让你从Sql Server转移到Oracle上去,
是增加100个新的DAL呢,还是增加一个Provider呢?到底是哪个代码量大?

  回复  引用  查看    
#34楼[楼主]2008-06-19 14:33 | T2噬菌体      
@紫色阴影

NBear的ORM还是比较好用的,其他功能没用过……

嗯,真正开发企业级应用肯定要使用现成的框架,不过在这个文章系列里,还是这样比较有利于初学者理解依赖注入的意义……

  回复  引用  查看    
#35楼[楼主]2008-06-19 14:34 | T2噬菌体      
--引用--------------------------------------------------
如果有了100个DAL类,突然让你从Sql Server转移到Oracle上去,
是增加100个新的DAL呢,还是增加一个Provider呢?到底是哪个代码量大?
--------------------------------------------------------

你这属于抬杠了,找个100个DAL的项目我看看……呵呵

再者,说实话,你给我提的很多意见我觉得特别有用。不过你不要忽略了一点,我这篇文章是写给初学者看的,不是写给要开发企业级应用的高手看的。我不是要告诉他们如何做一个项目,而是要让他们知道一些原理,例如依赖注入是怎么回事。

如果我直接使用框架,那么很多初学者就完全一头雾水了,因为他们根本不明白什么是依赖注入,也不知道那个框架怎么使用。请不要总站在你的高度看,请多为初学者想想。

我的文章只是要起到一个抛砖引玉的作用,当他们明白了基本原理,就可以自己学习各种框架的使用了。IoC框架固然重要,但是作为初学者,是不是朴素的实现对他们理解基本原理更有帮助呢

你要明白,我现在不是再做一个实际的项目,而是在向初学者解释一些分层架构的基本方法和原理。

  回复  引用    
#36楼2008-06-19 14:51 | MLY@[未注册用户]
--引用--------------------------------------------------
T2噬菌体: --引用--------------------------------------------------
如果有了100个DAL类,突然让你从Sql Server转移到Oracle上去,
是增加100个新的DAL呢,还是增加一个Provider呢?到底是哪个代码量大?
--------------------------------------------------------

你这属于抬杠了,找个100个DAL的项目我看看……呵呵

再者,说实话,你给我提的很多意见我觉得特别有用。不过你不要忽略了一点,我这篇文章是写给初学者看的,不是写给要开发企业级应用的高手看的。我不是要告诉他们如何做一个项目,而是要让他们知道一些原理,例如依赖注入是怎么回事。

如果我直接使用框架,那么很多初学者就完全一头雾水了,因为他们根本不明白什么是依赖注入,也不知道那个框架怎么使用。请不要总站在你的高度看,请多为初学者想想。

我的文章只是要起到一个抛砖引玉的作用,当他们明白了基本原理,就可以自己学习各种框架的使用了。IoC框架固然重要,但是作为初学者,是不是朴素的实现对他们理解基本原理更有帮助呢

你要明白,我现在不是再做一个实际的项目,而是在向初学者解释一些分层架构的基本方法和原理。
--------------------------------------------------------


说的不错,针对的对象不一样,初学者看挺好的

  回复  引用  查看    
#37楼2008-06-19 14:52 | westhot      
顶楼主 petshop 读起来比较累。
  回复  引用  查看    
#38楼2008-06-19 15:06 | 紫色阴影      
@T2噬菌体
呵呵 明白
而且我读书的时候远远达不到这种理解,即使用着MVC还是无法体会它的好处
顶lz,希望带来更多的好文章

  回复  引用  查看    
#39楼2008-06-19 15:08 | 紫色阴影      
@T2噬菌体
问一个问题,你在学校如何会有这些想法的呢?做了很多项目还是看书,看文章? 因为想着自己学生时代,总是徘徊在数据结构周围,对于分层和设计模式完全不明白

  回复  引用  查看    
#40楼[楼主]2008-06-19 15:19 | T2噬菌体      
@紫色阴影

这些东西学校里是不讲的。我刚开始就是做一些项目,当然做的比较幼稚,慢慢的不满足于单纯的编码,就开始对架构和设计模式等东西感兴趣,所以就买书看,像代码大全、Head First设计模式等,看完了再将自己学到的东西投入到所做的项目中,再总结。

除了考研那一年没接触这些东西,其他时间一直在学。当然,学校开始的数学、数据结构等基础类可能也很有用,不过老师讲的远远不够,我就经常找些经典的书看,如算法导论之类,然后就琢磨这些理论如何应用于实践。

我半年前开始从PHP转到.NET平台,三个月前开始接触分层,设计模式是一年前开始学的(因为考研复习,学得断断续续)。

  回复  引用  查看    
#41楼2008-06-19 15:48 | 艺林      
--引用--------------------------------------------------
T2噬菌体: --引用--------------------------------------------------
如果有了100个DAL类,突然让你从Sql Server转移到Oracle上去,
是增加100个新的DAL呢,还是增加一个Provider呢?到底是哪个代码量大?
--------------------------------------------------------

你这属于抬杠了,找个100个DAL的项目我看看……呵呵
--------------------------------------------------------
不是没有的!

  回复  引用    
#42楼2008-06-19 15:58 | WaitdDing[未注册用户]
半年的.Net学习时间,再加上不到一年的设计模式的研究,就有这样的高度,真是不简单!想想上大学那会儿,我还不知道在哪里玩泥巴呢.

不过LZ有一句话说得好:将理论应用到实际中去,然后总结.这个过程再迭代...这是个不错的学习方法,但我就是很难坚持下来,自愧不如啊:)

PS:从LZ的ID来看,应该对生化危机这款游戏比较有兴趣吧^_^

再问两个问题:
1.DependencyInjector.cs是哪一层的?还是只是一个辅助类?
2.如果业务逻辑发生了变化(这个变化可能是重大的),那么在此项目中应该作如何的修改?大致的修改流程是怎么样的?

  回复  引用  查看    
#43楼2008-06-19 16:13 | 金色海洋(jyk)      
说实在的,我还是一头雾水。
  回复  引用  查看    
#44楼2008-06-19 16:20 | 小生      
樓主寫的不錯。
但是在實際運用過程中﹐要有權衡﹐否則會有過度設計的危險(PS﹕就算有被替換的可能﹐也要考慮增加接口和注入的成本造成的復雜度與直接使用的簡單的比較)

  回复  引用  查看    
#45楼2008-06-19 16:25 | 紫色阴影      
@小生
的确,在设计的同时要考虑是否为以后扩展,如果现在引入复杂性和以后修改起来哪种成本更加大?

  回复  引用  查看    
#46楼2008-06-19 16:41 | henry      
其实设计的目的很重要是在于以后更容易修改和维护,对于接口约束的确起到一个很好的规则作用.但如果没有向高内聚低偶合进行靠拢的话...最终程序昨很能经得起考验.
对于怎样才能设计到高内聚低偶...我也不知道...我现在唯一的途径是通过不断的重构来实现代码的简洁.

  回复  引用  查看    
#47楼2008-06-19 19:07 | 皇帝的新装      
搞死人哦。
  回复  引用  查看    
#48楼2008-06-19 19:10 | 曲滨*銘龘鶽      
改 web.config 整个 应用重新启动监听 web.config 改变没意义
,这种业务用不用缓存没啥意义
用静态变量就可以搞定了;

而且这也不是抽象工厂,抽象工厂子类都是不同的;


  回复  引用  查看    
#49楼[楼主]2008-06-19 19:31 | T2噬菌体      
@WaitdDing

DependencyInjector是辅助类

业务逻辑层变化,只要接口不变,就没有问题

  回复  引用  查看    
#50楼[楼主]2008-06-19 19:33 | T2噬菌体      
@曲滨*銘龘鶽

第一点没看明白,可以详细说说吗?谢谢

第二点,这个应该说是抽象工厂的一种变体。

  回复  引用  查看    
#51楼2008-06-20 16:44 | 凯锐      
@T2噬菌体
去年三四月份的时候,我在学多层架构的时候,走过楼主相同类似的路。也写过一篇关於多层的文章
http://www.cnblogs.com/jinliangliu/archive/2007/03/12/672417.html" target="_new">http://www.cnblogs.com/jinliangliu/archive/2007/03/12/672417.html
不过,文笔没有楼主的好。
在楼主关於移植数据库的问题上,我采用的是新加一个数据访问类,比如说原先基於sql server的sqlDAL要移植成Access的就新加一个AccessDAL,再利用C#的RTTI反射生成实例

  回复  引用  查看    
#52楼2008-06-23 17:39 | 艺林      
  回复  引用    
#53楼2008-07-10 16:54 | Vin[未注册用户]
楼主,这个好像不是工厂吧,只是一般工厂模式,只是生产的都是抽象产品。



  回复  引用    
#54楼2008-07-10 17:13 | Vin[未注册用户]
而且好像并没必要每种情况都返回一个数据访问层类吧。是否应该把数据访问层整合一下。例如,对sql server,一般有sp,fun,view,table。那么数据访问的只需要包含查询view,table,调用sp,fun等几个通用方法就可以。接着数据层的工厂应该生产不同数据库类型的产品,如上面提到的server产品,或者mysql产品等等。
  回复  引用    
#55楼2008-07-10 17:16 | Vin[未注册用户]
当然实现方式时多种多样的,有时具体问题具体分析。
  回复  引用  查看    
#56楼2008-07-21 17:44 | Ray Wu      
--引用--------------------------------------------------
T2噬菌体: --引用--------------------------------------------------
<br>如果有了100个DAL类,突然让你从Sql Server转移到Oracle上去,
<br>是增加100个新的DAL呢,还是增加一个Provider呢?到底是哪个代码量大?
<br>--------------------------------------------------------
<br>
<br>你这属于抬杠了,找个100个DAL的项目我看看……呵呵
<br>
<br>再者,说实话,你给我提的很多意见我觉得特别有用。不过你不要忽略了一点,我这篇文章是写给初学者看的,不是写给要开发企业级应用的高手看的。我不是要告诉他们如何做一个项目,而是要让他们知道一些原理,例如依赖注入是怎么回事。
<br>
<br>如果我直接使用框架,那么很多初学者就完全一头雾水了,因为他们根本不明白什么是依赖注入,也不知道那个框架怎么使用。请不要总站在你的高度看,请多为初学者想想。
<br>
<br>我的文章只是要起到一个抛砖引玉的作用,当他们明白了基本原理,就可以自己学习各种框架的使用了。IoC框架固然重要,但是作为初学者,是不是朴素的实现对他们理解基本原理更有帮助呢
<br>
<br>你要明白,我现在不是再做一个实际的项目,而是在向初学者解释一些分层架构的基本方法和原理。
--------------------------------------------------------
100个dal的例子太多了,起码我开发的两个项目都达到了这个规模。

  回复  引用  查看    
#57楼[楼主]2008-07-21 21:31 | T2噬菌体      
@Ray Wu
呵呵,看来我真是井底之蛙了。谢谢您的提醒,以后我会注意到这个观念问题。
还有,可不可以请问一下,您参与的这两个项目是什么项目?

  回复  引用    
#58楼2008-08-06 12:38 | QQ:243287285[未注册用户]
//// <summary>
/// 取得数据访问层对象
/// </summary>
39 string dalName = (string)dal;
40 string fullClassName = dalName + "." + className;


39 行中,我个人认为的有可能在缓存中获取不到dalName.能在QQ给我指点吗


QQ:243287285

  回复  引用    
#59楼2008-08-06 13:49 | QQ:243287285[未注册用户]
Sorry 原来是我看错了

  回复  引用    
#60楼2008-08-15 16:37 | ayao[未注册用户]
我试着写了这个例子,运行时这条反射机制的语句失败 提示-----未能加载文件或程序集“GuestBook.SimpleBLL”或它的某一个依赖项。系统找不到指定的文件。bllObject = Assembly.Load(bllName).CreateInstance(fullClassName);
在web.config中添加的语句是
<add key="BLL" value="GuestBook.SimpleBLL"/>
一直没有解决这个问题,请问这是什么原因??谢谢

  回复  引用  查看    
#61楼[楼主]2008-08-16 10:22 | T2噬菌体      
检查一下你程序集的名称
  回复  引用  查看    
#62楼2008-09-02 12:42 | edrp.cn      
LZ的文笔不错,当然技术也很好,讲的通俗易懂,让我这个初学者真正的学到东西了,感谢!
  回复  引用  查看    
#63楼2008-09-11 16:11 | 搞IT的狐狸      
这样如何?

public sealed class CacheAccess<T>
{


public static void SaveToCache(string cacheKey, T cacheObject, CacheDependency dependency)
{
Cache cache = HttpRuntime.Cache;
cache.Insert(cacheKey, cacheObject, dependency);
}



public static T GetFromCache(string cacheKey)
{
Cache cache = HttpRuntime.Cache;
return (T) cache[cacheKey];

}
}

  回复  引用  查看    
#64楼2008-09-11 17:39 | 搞IT的狐狸      
public sealed class DependencyInjector<T>
{
public static T GetDALObject(string className)
{

string dal = CacheAccess<string>.GetFromCache("DAL");

if (dal == null)
{
CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.config"));
dal = ConfigurationManager.AppSettings["DAL"];
CacheAccess<string>.SaveToCache("DAL", dal, fileDependency);

}


string fullClassName = dal + "." + className;
T dalObject = CacheAccess<T>.GetFromCache(className);

if (dalObject==null)
{
CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.config"));

dalObject = (T)Assembly.Load(dal).CreateInstance(fullClassName);

CacheAccess<T>.SaveToCache(className, dalObject, fileDependency);
}


return dalObject;

}


}

  回复  引用  查看    
#65楼[楼主]2008-09-22 19:43 | T2噬菌体      
@搞IT的狐狸
你使用泛型想达到一个什么目的呢?

  回复  引用  查看    
#66楼2008-09-23 12:32 | 搞IT的狐狸      
你的方法 是通过传入的字符 找到命名空间类字符 放到缓存里。有时候我们是不是也要 直接把 对象 放到 换存中 饿。。。我也说不大具体。。。
  回复  引用    
#67楼2009-03-15 12:32 | -摇光-
DependencyInjector代码冗余哦,两个方法可以合并成一个的....



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1225223




相关文章:

相关链接: