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

  • 相关阅读:
    C. Shaass and Lights 解析(思維、組合)
    D. Binary String To Subsequences(队列)(贪心)
    CodeForces 1384B2. Koa and the Beach (Hard Version)(贪心)
    CodeForces 1384B1. Koa and the Beach (Easy Version)(搜索)
    CodeForces 1384C. String Transformation 1(贪心)(并查集)
    CodeForces 1384A. Common Prefixes
    POJ-2516 Minimum Cost(最小费用最大流)
    POJ3261-Milk Patterns(后缀数组)
    HDU-1300 Pearls(斜率DP)
    HDU-4528 小明系列故事-捉迷藏(BFS)
  • 原文地址:https://www.cnblogs.com/kcitwm/p/2047331.html
Copyright © 2011-2022 走看看