`
leogao_emcom
  • 浏览: 83218 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

一个简单的基于约定优于配置(Coc)的对象工厂实现

阅读更多
Baidu 写道
约定优于配置(Convention Over Configuration)

约定优于配置是一个简单的概念。 系统,类库,框架应该假定合理的默认值,而非要求提供不必要的配置。 流行的框架如 Ruby on Rails 和 EJB3 已经开始坚持这些原则,以对像原始的 EJB 2.1 规范那样的框架的配置复杂度做出反应。 一个约定优于配置的例子就像 EJB3 持久化,将一个 特殊的Bean持久化,你所需要做的只是将这个类标注为 @Entity 。 框架将会假定表名和列名是基于类名和属性名。 系统也提供了一些钩子,当有需要的时候你可以重写这些名字,但是,在大部分情况下,你会发现使用框架提供的默认值会让你的项目运行的更快。
 

上午闲暇的时候,开发了一个简单的基于Coc策略的对象工厂。目的是验证一下Coc的基本实现逻辑.

因为Coc是一种比较好的简单化DI实现、配置和维护的好方式,虽然它代替不了XML来说明依赖关系,因为对于值类型注入

和接口注入它还无能为力,但是为大大简化DI的实现、配置以及维护提供很好的改进,实际中应该将Coc和XML声明的方式

结合起来使用。下面是我写的一个简单的实现,不过后期将不断改善和丰富。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace DotNetConsole
{
	public delegate void InitObjectRelationShip (object thisObj);
	public class ObjectFactory
	{
		private static Random NextObj = null;

		public static object Create (Type ObjectType, InitObjectRelationShip InitMethod)
		{
			object CachedObject = CreateObject (ObjectType, InitMethod);
			if (NextObj == null)
				NextObj = new Random ();
			if (ObjectPoolService.GetCahce ().ContainsKey (ObjectType.ToString ())) {
				ObjectPoolService.SetCurrentPoolInUse (true);
				if (ObjectPoolService.GetCahce ()[ObjectType.ToString ()].Count < ObjectPoolService.GetMaxSize ()) {
					ObjectPoolService.GetCahce ()[ObjectType.ToString ()].Add (CachedObject);
				}
				
				int index = (int)NextObj.Next (ObjectPoolService.GetCahce ()[ObjectType.ToString ()].Count);
				return ObjectPoolService.GetCahce ()[ObjectType.ToString ()][index];
				
			} else {
				
				if (ObjectPoolService.GetMaxSize () > ZERO_VALUE) {
					ObjectPoolService.SetCurrentPoolInUse (true);
					ObjectPoolService.GetCahce ().Add (ObjectType.ToString (), new List<object> ());
					ObjectPoolService.GetCahce ()[ObjectType.ToString ()].Add (CachedObject);
				}
				
			}
			ObjectPoolService.SetCurrentPoolInUse (false);
			return CachedObject;
			
		}
		///in the future ,will implement proxy object not real object and 
		///base on proxy way, for object's method calling will be done as parall way.
		private static object CreateObject (Type ObjectType, InitObjectRelationShip InitMethodDef)
		{
			object FirstHeadObject = Activator.CreateInstance (ObjectType);
			if (InitMethodDef == null) {
				Type[] interfaceTypes = ObjectType.GetInterfaces ();
				if (interfaceTypes.Length != 0) {
					foreach (Type interfaceSubType in interfaceTypes) {
						if (interfaceSubType.Equals (typeof(IUserModeObjectInitor))) {
							((IUserModeObjectInitor)FirstHeadObject).Init ();
						}
					}
					
				}
				PropertyInfo[] proInfos = ObjectType.GetProperties ();
				if (proInfos.Length != 0) {
					foreach (PropertyInfo pro in proInfos) {
						if (pro.GetValue (FirstHeadObject, null) == null) {
							SetDepthObjectRelationShip (FirstHeadObject, pro);
						}
					}
				}
			} else {
				
				InitMethodDef (FirstHeadObject);
			}
			return FirstHeadObject;
		}
		private static void SetDepthObjectRelationShip (object MainObject, PropertyInfo PropertyType)
		{
			
			object PropertyObject = Activator.CreateInstance (PropertyType.PropertyType);
			PropertyType.GetSetMethod ().Invoke (MainObject, new object[] { PropertyObject });
			PropertyInfo[] innerProps = PropertyType.PropertyType.GetProperties ();
			if (innerProps.Length != 0) {
				foreach (PropertyInfo innerProerty in innerProps) {
					SetDepthObjectRelationShip (PropertyObject, innerProerty);
				}
			}
			
		}
		private const int ZERO_VALUE = 0;
	}
}

在ObjectFactory中,还使用了一个基于无状态对象的ObjectPoolService(实现在下面,暂时提供最简单的实现),目的是提供对象重用率减少内存占用有量,并且提供随机的对象获取机制,因为客户程序不关心同一类型的多个对象哪一个为其提供服务。并且在MaxSize=0时,可以不使用ObjectPoolService而直接Create Object. MaxSize越大,Pool中某一个对象的重用机会就越小,并且内存占用率也比较高,所以MaxSize可以用来微调内存占有率和重用几率的配置。

值得注意的是Create方法中提供一个类型为

InitObjectRelationShip

的委托参数,它可以由调用者指定对象关系组装的方式(如果不想使用Coc的话,或者结合XML配置和Coc的话,可以看一下下面的测试代码),组合各种DI策略就比较灵活了.

 

另外还设计了一个叫做IUserModeObjectInitor的接口,用于跳过组装过程,开发者自己组装对象关系,但是侵入性比较强,

建议使用ObjectFactory的Create方法中的委托参数干这件事情,这里保留这个接口的目的是为了方式灵活,不过以方法的委托参数的处理为优先!

using System;
namespace DotNetConsole
{
	public interface IUserModeObjectInitor
	{
		void Init();
	}
}

为了提高性能,还设计了一个极为简单的Cache:

using System;
using System.Collections.Generic;
namespace DotNetConsole
{
	//use cassanadra db repleace in the future.
	public class ObjectPoolService
	{
		private static volatile Dictionary<string,List<object>> m_ObjectCache=null;
		private static int m_MaxSize=0;
		private static bool m_IsInUse=false;
		public static Dictionary<string, List<object>> GetCahce ()
		{
			if (m_ObjectCache == null)
				m_ObjectCache = new Dictionary<string, List<object>> ();
			return m_ObjectCache;
		}
		public static void SetMaxSize (int Size)
		{
			m_MaxSize = Size;
		}
		public static int GetMaxSize ()
		{
			return m_MaxSize;
		}
		public static void SetCurrentPoolInUse (bool isInUse)
		{
			m_IsInUse = isInUse;
		}
		public static bool GetCurrentPoolUsingState ()
		{
			return m_IsInUse;
		}
		public static void ShutdownPool ()
		{
			if (!m_IsInUse)
			{
				m_ObjectCache.Clear ();
			}
		}
		
		
	}
}

 

测试的代码:

using System;
using System.Reflection;
namespace DotNetConsole
{
	class MainClass
	{
		//statefulless Object gen! can reduce mem.
		public static void Main (string[] args)
		{
			ObjectPoolService.SetMaxSize (100);
			double timestart = DateTime.Now.Millisecond;
			((OrderService)ObjectFactory.Create (typeof(OrderService), x =>
					((OrderService)x).DAOObject = (OrderDAO)ObjectFactory.Create (typeof(OrderDAO), null))).ShowInfo ();
			for (int i = 0; i < 1000; i++)
			{
				((OrderService)ObjectFactory.Create (typeof(OrderService), null)).ShowInfo ();
			
			}
			ObjectPoolService.SetCurrentPoolInUse (false);
			ObjectPoolService.ShutdownPool ();
			double timeend= DateTime.Now.Millisecond;
			Console.WriteLine (timeend-timestart);
			Console.ReadLine();
		
		}
		
		
	}
}

 

以上,基本思路就是先排除用XML来定义类之间的依赖关系,当前先暂时开发一个最基本的只有基于Coc策略的基本对象工厂,实现方式很简单,就是利用反射获取目标类型的属性列表,然后取得属性的类型(暂时只是引用类型),然后还是利用反射实例化对应属性类型的对象并注入到目标对象中,然后递归地这样处理,所有依赖的对象都初始化并组装进来。

当然这是一个最基本的实现。基于这个在考虑拓展,是比较好的方式,逐步演化比较好。后续还有很多工作要做,

处理这个简单的工厂,必须以此为基础开发达到能使用级别的分布式对象Cache、分布式的层次型的Object容器、基于代理的对象创建、AOP、由于要采用Emit来创建代理对象的方式来实现基于代理的类型创建,然后将此”虚拟“出来的类型传给这个ObjectFactory来生成对象,那么有可能在“虚拟”出来的类型(代理)中插入任何想干的事情,比如前面的AOP或者只有在调用一个方法时在实例化目标“能干活”的真实对象(延迟加载),另外能够将代理类用Emit伪装成WCF的服务类型(插入服务契约等Attribute等),那么就可以实现对象服务的发出(向网络公布成服务)的功能,以上这些增强,我会逐步加入,都是以当前这个ObjectFactory作为最底层的基础的。后续的改进代码会陆续登录上来的

 

0
3
分享到:
评论
1 楼 gbllty1981 2011-08-11  
 

相关推荐

Global site tag (gtag.js) - Google Analytics