zoukankan      html  css  js  c++  java
  • 完美开发模型之贫血模型参考(I)

    不用争论哪种模型好,而是在每种模型下面怎么样做到最好.
    对于企业来说,高效的赢利才是根本,在开发过程中应该追求中庸之道才能达到技术与赢利效率的平衡. 软件过于平铺简单会导致后期维护开发成本大大提升,尽管前期看起来很快;软件设计过于复杂导致整个过程有很大的成本浪费. 具体点应该坚持两个原则:

    1. 绝对避免过程式开发:停留在脚本语句,asp之类解释性语言的编程模式上不可取.

    2. 尽量避免引入各种框架: 编程模型跟着官方走,别找一大堆外在框架堆积在系统中.

    对应的采取的方法是:

    1. 充分利用现代的,成熟的面各对象的语言,充分利用三个特性:封装,继承,多态. 就能完美的解决80%的问题,剩下20%的问题由设计模式解决.

    2. 充分理解各种框架的原理,然后根据应用规模自己模拟其核心实现一个精简版本,就能完全解决各种性能,扩展性,可靠性,效率等软件质量方面的问题.

    如果不按照上面做也会导致两个非常糟糕的局面.

    1. 随着项目的庞大和时间和流长,代码累积乱成麻:一是不敢轻易对核心业务的乱代码进行升级修改,二是在修改的时候要花费大量时间去理解原来过程式代码,三是非常多的垃圾无用代码没人能清理,大量重复代码没有敢重构.

    2.随着项目的庞大和时间和流长,各种框架乱成麻:一是初始感觉良好的框架多半会出现严重的性能问题.二是可控性上会失控:控制不了细粒度实现,控制不了框架的完整性,会被来来去去的各种种色色的人搞得乱七八糟.三是新人进来会花费大量成本在框架学习和理解上,更要命的是学习前人破坏得面目全非的一个烂框架.

    最终的解决方案就是写一个中庸的,真正面向对象的,现代的,半自动化的,半熟的程序结构.写好之后,任何项目,任何公司直接复制,通过简单的复制替换方法就能把底层物件全部搭建好.
    下面以.NET为例.

    三层基础结构: Entity,DataAccess,Components


    Data.dll
    数据帮助类:

    using System;
    using System.Data;
    using System.Data.Common;
    using System.Configuration;
    using WQFree.Configuration;
    using System.Data.OracleClient;

    namespace WQFree.Data
    {

        public class DataHelper
        {
            protected ConnectionStringSettings _connectionStrings;
            protected DbProviderFactory factory;

            protected bool autoClose = true;
            protected IDbConnection _connection = null;

            public bool AutoClose
            {
                get { return autoClose; }
                set { autoClose = value; }
            }

            public IDbConnection Connection
            {
                get
                {
                    if (null == _connection)
                    {
                        IDbConnection conn = factory.CreateConnection();
                        conn.ConnectionString = _connectionStrings.ConnectionString;
                        conn.Open();
                        _connection = conn;
                    }
                    else if (_connection.State != ConnectionState.Open)
                        _connection.Open();
                    return _connection;
                }
                set
                {
                    _connection = value;
                }
            }

            public ConnectionStringSettings ConnectionStrings
            {
                get { return _connectionStrings; }
                set { _connectionStrings = value; }
            }

            public DataHelper(string providerName, IDbConnection connection)
            {
                this._connection = connection;
                this._connectionStrings = new ConnectionStringSettings(providerName, connection.ConnectionString, providerName);
                Init();
            }

            public DataHelper(string providerName, IDbConnection connection, bool autoClose)
            {
                this.autoClose = autoClose;
                this._connection = connection;
                this._connectionStrings = new ConnectionStringSettings(providerName, connection.ConnectionString, providerName);
                Init();
            }

            public DataHelper(ConnectionStringSettings connectionStrings)
            {
                this._connectionStrings = connectionStrings;
                Init();
            }

            protected void Init()
            {
                if (null == factory)
                {

                    factory = DbProviderFactories.GetFactory(_connectionStrings.ProviderName);
                }
            }

            public IDataReader ExcuteDataReader(string cmdText, CommandType cmdType, params IDataParameter[] parameters)
            {
                IDbConnection conn = Connection;
                DbCommand cmd = conn.CreateCommand() as DbCommand;
                cmd.CommandText = cmdText;
                cmd.CommandType = cmdType;
                cmd.Parameters.AddRange(parameters);
                if (!autoClose)
                    return cmd.ExecuteReader(CommandBehavior.CloseConnection);
                return cmd.ExecuteReader();
            }

            public object ExecuteScalar(string cmdText, CommandType cmdType, params IDataParameter[] parameters)
            {
                IDbConnection conn = Connection;
                DbCommand cmd = conn.CreateCommand() as DbCommand;
                cmd.CommandText = cmdText;
                cmd.CommandType = cmdType;
                cmd.Parameters.AddRange(parameters);
                object o = cmd.ExecuteScalar();
                if (autoClose) conn.Close();
                return o;
            }

            public DataSet ExecuteDataSet(string cmdText, CommandType cmdType, string tableName, params IDataParameter[] parameters)
            {
                IDbConnection conn = Connection;
                DbCommand cmd = conn.CreateCommand() as DbCommand;
                cmd.Parameters.AddRange(parameters);
                cmd.CommandText = cmdText;
                cmd.CommandType = cmdType;
                DbDataAdapter da = factory.CreateDataAdapter();
                da.SelectCommand = cmd;
                DataSet ds = new DataSet(tableName);
                da.Fill(ds);
                if (autoClose) conn.Close();
                return ds;
            }

            public int Fill(DataSet ds, string cmdText, CommandType cmdType, params IDataParameter[] parameters)
            {
                IDbConnection conn = Connection;
                DbCommand cmd = conn.CreateCommand() as DbCommand;
                cmd.Parameters.AddRange(parameters);
                cmd.CommandText = cmdText;
                cmd.CommandType = cmdType;
                DbDataAdapter da = factory.CreateDataAdapter();
                da.SelectCommand = cmd;
                da.AcceptChangesDuringFill = false;

                int n = da.Fill(ds);
                if (autoClose) conn.Close();
                return n;
            }

            public int ExecuteNonQuery(string cmdText, CommandType cmdType, params IDataParameter[] parameters)
            {
                IDbConnection conn = Connection;
                DbCommand cmd = conn.CreateCommand() as DbCommand;
                cmd.CommandText = cmdText;
                cmd.CommandType = cmdType;
                cmd.Parameters.AddRange(parameters);
                int n = cmd.ExecuteNonQuery();
                if (autoClose) conn.Close();
                return n;
            }

            public virtual  IDbDataParameter CreateParameter(string name, object value)
            {
                DbParameter p = factory.CreateParameter();
                p.ParameterName = name;
                p.Value = value;
                return p;
            }

            public virtual IDbDataParameter CreateParameter(string name, DbType type, object value)
            {
                DbParameter p = factory.CreateParameter();
                p.ParameterName = name;
                p.DbType = type;
                p.Value = value;
                return p;
            }

            public virtual IDbDataParameter CreateParameter(string name, ParameterDirection direction, DbType type)
            {
                DbParameter p = null;
                p=factory.CreateParameter();
                p.DbType = type;
                p.Direction = direction;
                p.ParameterName = name;
                p.DbType = type;
                return p;
            }

            public virtual IDbDataParameter CreateParameter(string name, ParameterDirection direction, DbType type,int size)
            {
                DbParameter p = null;
                p = factory.CreateParameter();
                p.DbType = type;
                p.Direction = direction;
                p.ParameterName = name;
                p.DbType = type;
                p.Size = size;
                return p;
            }

            public virtual IDbDataParameter CreateParameter(string name, DbType type, int size, object value)
            {
                DbParameter p = factory.CreateParameter();
                p.ParameterName = name;
                p.Size = size;
                p.DbType = type;
                p.Value = value;
                return p;
            }

            public virtual IDbDataParameter CreateParameter(string name, DbType type, ParameterDirection direction, object value)
            {
                DbParameter p = factory.CreateParameter();
                p.ParameterName = name;
                p.DbType = type;
                p.Direction = direction;
                p.Value = value;
                return p;
            }

            public virtual IDbDataParameter CreateParameter(string name, DbType type, ParameterDirection direction, int size, object value)
            {
                DbParameter p = factory.CreateParameter();
                p.ParameterName = name;
                p.DbType = type;
                p.Direction = direction;
                p.Size = size;
                p.Value = value;
                return p;
            }

            

        }
    }


    数据访问对象基类:
    using System;
    using System.Data;
    using System.Reflection;
    using System.Configuration;
    using System.Reflection.Emit;
    using System.Collections.Generic;

    namespace WQFree.Data
    {
        public class DAO<T> : IDisposable  
        {
            protected DataHelper hp = null;
          
            public IDbConnection Connection
            {
                get
                {
                    return hp.Connection;
                }
                set
                {
                    hp.Connection = value;
                }
            }

            public bool AutoClose
            {
                get { return hp.AutoClose; }
                set { hp.AutoClose = value; }
            }

            public DAO() { hp = HelpFactory.Instance(); }

            public DAO(ConnectionStringSettings connectionStrings)
            {
                hp = HelpFactory.Instance(connectionStrings);
            }

            public DAO(string providerName, IDbConnection connection)
            {
                hp = HelpFactory.Instance(providerName, connection);
            }

            public DAO(string providerName, IDbConnection connection, bool mustClose)
            {
                hp = HelpFactory.Instance(providerName, connection, mustClose);
            }

            public List<T> BuildList(DataTable dt)
            {
                return EntityBuilder<T>.BuildList(dt);
            }

            public T Build(DataTable dt)
            {
                return EntityBuilder<T>.Build(dt);
            }

            public T Build(DataRow row)
            {
                return EntityBuilder<T>.Build(row);
            }


            public List<T> BuildList(IDataReader dr)
            {
                return EntityBuilder<T>.BuildList(dr);
            }

            public T Build(IDataReader dr)
            {
                return EntityBuilder<T>.Build(dr);
            }

            public void Close()
            {
                IDbConnection conn = Connection;
                if (conn != null && conn.State == ConnectionState.Open)
                    conn.Close();
            }


            #region IDisposable 成员

            public void Dispose()
            {
                Close();
            }

            #endregion
        }
    }


    高性能实体映射类:
    using System;
    using System.Data;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Collections.Generic;

    namespace WQFree.Data
    {
        public class EntityBuilder<T>
        {
            private static readonly MethodInfo getValueMethod = typeof(DataRow).GetMethod("get_Item", new Type[] { typeof(int) });
            private static readonly MethodInfo isNullMethod = typeof(DataRow).GetMethod("IsNull", new Type[] { typeof(int) });
            private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
            private static readonly MethodInfo getRecordValueMethod = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
            private delegate T LoadDataRow(DataRow dataRow);
            private LoadDataRow dataRowHandler;
            private delegate T LoadRecord(IDataRecord dataRecord);
            private LoadRecord recordHander;

            private static Dictionary<string, EntityBuilder<T>> builders = new Dictionary<string, EntityBuilder<T>>();
            
            public T BuildEntity(DataRow dataRow)
            {
                return dataRowHandler(dataRow);
            }

            public T BuildEntity(IDataRecord dataRecord)
            {
                return recordHander(dataRecord);
            }

            private static EntityBuilder<T> CreateBuilder(DataRow dataRow)
            {
                Type type = typeof(T);
                string key="Row:"+type.Name;
                if (builders.ContainsKey(key))
                    return builders[key];
                EntityBuilder<T> dynamicBuilder = new EntityBuilder<T>();
                DynamicMethod method = new DynamicMethod("DataRowCreateT", type, new Type[] { typeof(DataRow) }, typeof(T), true);
                ILGenerator generator = method.GetILGenerator();
                LocalBuilder result = generator.DeclareLocal(type);
                generator.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
                generator.Emit(OpCodes.Stloc, result);
                int len = dataRow.ItemArray.Length;
                for (int i = 0; i < len; i++)
                {
                    System.Reflection.PropertyInfo propertyInfo = type.GetProperty(dataRow.Table.Columns[i].ColumnName);
                    Label endIfLabel = generator.DefineLabel();
                    if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
                    {
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldc_I4, i);
                        generator.Emit(OpCodes.Callvirt, isNullMethod);
                        generator.Emit(OpCodes.Brtrue, endIfLabel);
                        generator.Emit(OpCodes.Ldloc, result);
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldc_I4, i);
                        generator.Emit(OpCodes.Callvirt, getValueMethod);
                        generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
                        generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                        generator.MarkLabel(endIfLabel);
                    }
                }
                generator.Emit(OpCodes.Ldloc, result);
                generator.Emit(OpCodes.Ret);
                dynamicBuilder.dataRowHandler = (LoadDataRow)method.CreateDelegate(typeof(LoadDataRow));
                builders.Add(key, dynamicBuilder);
                return dynamicBuilder;
            }

            private static EntityBuilder<T> CreateBuilder(IDataRecord dataRecord)
            {
                Type type = typeof(T);
                string key = "Record:" + type.Name;
                if (builders.ContainsKey(key))
                    return builders[key];
                EntityBuilder<T> dynamicBuilder = new EntityBuilder<T>();
                DynamicMethod method = new DynamicMethod("DataRecordCreateT", type, new Type[] { typeof(IDataRecord) }, typeof(T), true);
                ILGenerator generator = method.GetILGenerator();
                LocalBuilder result = generator.DeclareLocal(type);
                generator.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
                generator.Emit(OpCodes.Stloc, result);
                int len = dataRecord.FieldCount - 1;
                for (int i = 0; i < len; i++)
                {
                    PropertyInfo propertyInfo = type.GetProperty(dataRecord.GetName(i));
                    Label endIfLabel = generator.DefineLabel();
                    if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
                    {
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldc_I4, i);
                        generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                        generator.Emit(OpCodes.Brtrue, endIfLabel);
                        generator.Emit(OpCodes.Ldloc, result);
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldc_I4, i);
                        generator.Emit(OpCodes.Callvirt, getRecordValueMethod);
                        generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
                        // generator.Emit(OpCodes.Unbox_Any, dataRecord.GetFieldType(i));
                        generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                        generator.MarkLabel(endIfLabel);
                    }
                }
                generator.Emit(OpCodes.Ldloc, result);
                generator.Emit(OpCodes.Ret);
                dynamicBuilder.recordHander = (LoadRecord)method.CreateDelegate(typeof(LoadRecord));
                builders.Add(key, dynamicBuilder);
                return dynamicBuilder;
            }

            public static List<T> BuildList(DataTable dt)
            {
                List<T> list = new List<T>();
                if (dt == null || dt.Rows.Count==0) return list;
                EntityBuilder<T> builder = EntityBuilder<T>.CreateBuilder(dt.Rows[0]);
                foreach (DataRow info in dt.Rows)
                    list.Add(builder.BuildEntity(info));
                dt.Dispose(); dt = null;
                return list;
            }

            public static T Build(DataRow row)
            {
                EntityBuilder<T> builder = CreateBuilder(row);
                return builder.BuildEntity(row);
            }

            public static T Build(DataTable dt)
            {
                EntityBuilder<T> builder = CreateBuilder(dt.Rows[0]);
                return builder.BuildEntity(dt.Rows[0]);
            }

            public static List<T> BuildList(IDataReader dr)
            {
                EntityBuilder<T> builder = CreateBuilder(dr);
                List<T> list = new List<T>();
                if (dr == null) return list;
                while (dr.Read())
                    list.Add(builder.BuildEntity(dr));
                return list;
            }

            public static T Build(IDataReader dr)
            {
                EntityBuilder<T> builder = CreateBuilder(dr);
                if (dr.Read())
                    return builder.BuildEntity(dr);
                return default(T);
            }

        }
    }


    DataAccess.dll
    具体实现类:

     public class UserDao : DAO<User>
        {
            const string saveSP = "PKG_WQFree.UserSaveSP";

            public int Save(User entity)
            {
                IDbDataParameter[] pars = new IDbDataParameter[]
                {
                    hp.CreateParameter("InEntityId",entity.EntityId), 
                    hp.CreateParameter("InUserName",entity.UserName)
                };                     
                return hp.ExecuteNonQuery(saveSP, CommandType.StoredProcedure, pars);
            }

            public int Save(List<User> entities)
            {
                int ret = 0;
                this.AutoClose = false;
                using (IDbConnection conn = Connection)
                {
                    foreach (User art in entities)
                    {
                        ret += Save(art);
                    }
                }
                return ret;
            }

            public int Save(DataTable datas)
            {
                List<User> entities = this.BuildList(datas);
                return Save(entities);
            }
         }


    Components.dll
    组件层:
     public class UserMgr
        {
            UserDao dao = new UserDao();

            public int Save(User entity)
            {
                try
                {
                    return dao.Save(entity);
                }
                catch (Exception e)
                {
                    Log.Error("保存User失败:" + e.Message);
                }
                return -1;
            }

            public List<User> BuildList(DataTable dt)
            {
                try
                {

                    return dao.BuildList(dt);
                }
                catch (Exception e)
                {
                    Log.Error("获取User列表失败:" + e.Message);
                }
                return new List<User>();
            }

            public int Save(DataTable datas)
            {
                try
                {
                    return dao.Save(datas);
                }
                catch (Exception e)
                {
                    Log.Error("保存User失败:" + e.Message);
                }
                return -1;
            }
        }

    上面几层次的基本实现,严格按照结构,格式和风格来写,不要做任何改变,不要加入任何业务逻辑:可用复制替换的方法快速开发完毕,就是一个高效可完全控制核心代码的ORM.

    上面的实现中留给读者两个小作业题自行解决:
    1. 兼容Oracle 和Sql数据库,可以通过DataHelperFactory来实现,怎么解决OracleType和DbType之间的映射问题?
    2. 在"实体映射类"中怎么样解决Oracle和SQL对应实体属性名称大小写问题?


    请期待下一节:完美开发模型之贫血模型参考(II):Service/Facade/UI层

    请期待下一篇:完美开发模型之领域模型参考

    如有疑问请发: wopani@gmail.com

  • 相关阅读:
    Autodesk vasari Design better buildings
    NOOK2刷机成功
    使用DirectPlay进行网络互联(2)
    程序员的灯下黑:不要忘记你的目标
    【ZT】中西医的区别
    D3D中公告板的使用示例
    使用DirectPlay进行网络互联(1)
    使用DirectPlay进行网络互联(4)
    计算几何常用算法概览
    DirectX9.0教程之ID3DXSprite篇[转载]
  • 原文地址:https://www.cnblogs.com/kcitwm/p/2047331.html
Copyright © 2011-2022 走看看