• 企业代码


    企业代码需要我们用以下方式重新看待代码

    一、模块性   

    代码单元通常表现为类或类型。它们是基于特定目标而设计的。各个代码单元间的交互方式既要能达到较大的期望目标,    又不能违背对它们进行划分的准则。模块化不仅是针对可重用性的代码分离,同时也要求很强的松散耦合度。

    二、松散耦合的类    

    如果代码单元需要使用来自系统其他部分的服务,那么这些服务应该抽象地由传递到该单元中。创建所需的依懒不应该是该单元的职责。  如果针对代码单元编写单元测试很方便,就证明其松散耦合度很低。

    看下面的示例:

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.OleDb;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        public class Program
        {
            const double basePrice = 35.00;
            static void Main(string[] args) {
                DataSet ds = new DataSet();
                OleDbCommand cmd = new OleDbCommand();
                string sql = "Select c.LastName,c.FristName,c.MiddleName,c.CustmerRegion,e.EmailAddress from Customers c inner join Email e on c.ID = e.CustomerID Order by c.LastName ASC";
                string name = "";
                double price = 0.0;
                OleDbConnection conn = new OleDbConnection();
                OleDbDataAdapter adapter = new OleDbDataAdapter();
                cmd.Connection = conn;
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = sql;
                adapter.SelectCommand = cmd;
    
                try
                {
                    adapter.Fill(ds);
                }
                catch (Exception e) {
                    Console.WriteLine(e.Message);
                }
    
                foreach (DataRow dr in ds.Tables[0].Rows) {
                    name = String.Format("{0},{1}{2}", dr["LastName"], dr["FirstName"], dr["MiddleName"]);
                    switch (dr["CustomerRegion"].ToString()) { 
                        case "1":
                            price = (0.9 * basePrice);
                            break;
                        case "2":
                            price = (0.85 * basePrice);
                            break;
                        case "3":
                            price = (0.8 * basePrice);
                            break;
                    }
    
                    Console.WriteLine(String.Format("Customer name:{0} Customer Email Address:{1} Customer's Price:{3}", name, dr["EmailAddress"].ToString(), price));
                }
            }
    
        }
    }

    Program中的代码可以正常工作,但不是良好设计的代码。它不仅严重违背了模块化规则,还违背了松散耦合的基本准则。  在本例中,我们无法编写单元测试。

     对于同一示例,一个好的多的版本可能要分解为不同的类型,每个类型能够符合模块化和松散耦合的规则。

    首先,我们创建一个简单的数据实用工具类型:

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.OleDb;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        /// <summary>
        /// 一个简单的数据实用工具类型
        /// 执行简单的数据提取,并以ADO.NET数据行集的形式返回提取的数据
        /// </summary>
        public class DataUtility
        {
            private string _connectionString;
            private DataSet _ds;
            private OleDbCommand _cmd;
            private OleDbConnection _conn;
            private OleDbDataAdapter _adapter;
    
            public DataUtility(string connectionString) {
                _connectionString = connectionString;
            }
    
            public DataRowCollection GetData(string sql) {
                _ds = new DataSet();
                _conn = new OleDbConnection(_connectionString);
                _cmd = new OleDbCommand();
                _cmd.Connection = _conn;
                _cmd.CommandType = CommandType.Text;
                _cmd.CommandText = sql;
                _adapter = new OleDbDataAdapter(_cmd);
    
                try
                {
                    _adapter.Fill(_ds);
                }
                catch 
                { 
                   //handle exception and log the event
                }
    
                return _ds.Tables[0].Rows;
            }
        }
    }
    View Code

    下一步,我们创建一个完成基于基本价格进行打折率计算。由于这些计算代表一组业务规则,因此,实际上不同的上下文下可能需要不同的计算类。因此真正要做的是定义一组规则,抽象地代表这些计算类。可以使用下面这样一个接口:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        /// <summary>
        /// 定义一组规则,抽象地代表所有计算类
        /// </summary>
        public interface iCalcList
        {
             double this[int region] { get; }
            double GetPrice(int region);
            double BasePrice { get; set; }
        }
    }
    View Code

    在建立企业系统时,该抽象接口是一个重要的设计要素。抽象接口是类型解除关联的流行方法。此时,我们需要创建一个打折列表类:

    using System;
    using System.Collections.Generic;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        public class DiscountList:iCalcList
        {
            private Dictionary<int, double> _rates;
            private double _basePrice;
    
            public double BasePrice {
                get { return this._basePrice; }
                set { this._basePrice = value; }
            }
    
            public DiscountList() {
                _rates = new Dictionary<int, double>();
                _rates.Add(1, 0.9);
                _rates.Add(2, 0.85);
                _rates.Add(3, 0.8);
            }
    
            public double this[int region] {
                get { return _rates[region]; }
            }
    
            public double GetPrice(int region) {
                return _rates[region] * BasePrice;
            }
        }
    }
    View Code

    我们需要建立的下一个类应该实现来自数据行的文本格式化。我们需要循环处理每个数据行,提取相关列值,根据客户所在的区域计算相应的价格,然后打印成一个文本行。这个类同样代表一个业务逻辑单元,因此,我们要先定义一个代表这个抽象类型的接口,然后实现文本格式化器。

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        /// <summary>
        /// 数据行的文本格式化抽象逻辑
        /// </summary>
        public interface iTextFormatter
        {
            string GetFormattedText();
        }
    }
    View Code

    下面我们建立文本格式化器本身的代码:

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Text;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        /// <summary>
        /// 文本格式化器
        /// </summary>
        public class DataToTextFormatter:iTextFormatter
        {
            private DataRowCollection _rows;
            private iCalcList _rateCalculator;
    
            public DataToTextFormatter(DataRowCollection rows, iCalcList rateCalculator) {
                _rows = rows;
                _rateCalculator = rateCalculator;
            }
    
            private string FormatLineEntry(DataRow dr) {
                string name = String.Format("{0},{1}{2}", dr["LastName"], dr["FirstName"], dr["MiddleName"]);
    
                double price = _rateCalculator.GetPrice((int)(dr["CustomerRegion"]));
                string email = dr["EmailAddress"].ToString();
    
                return String.Format("Customer name:{0} Customer Email Address:{1} Customer's Price:{3}", name, email, price);
    
            }
    
            public string GetFormattedText() {
                StringBuilder sb = new StringBuilder();
                foreach (DataRow dr in _rows) {
                    sb.Append(FormatLineEntry(dr));
                }
                return sb.ToString();
            }
        }
    }
    View Code

    仔细观察示例会发现,构造函数需要一个iCalcList的一个实例,那么构造函数可以很容易的接受iCalcList的子类的一个实例。

    下面我们封装一个完成任务的所有单元,我们也可以在控制台应用程序的Main方法中调用它们:

    using System;
    using System.Collections.Generic;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02
    {
        /// <summary>
        /// 用于执行相关动作
        /// </summary>
        public class ListPresenter
        {
            private DataUtility _dUtil;
            private iCalcList _dList;
            private iTextFormatter _formatter;
    
            public ListPresenter(DataUtility dUtil,iCalcList dList,iTextFormatter formatter) {
                this._dList = dList;
                this._dUtil = dUtil;
                this._formatter = formatter;
            }
    
            public string GetList() {
                string sql = "Select c.LastName,c.FristName,c.MiddleName,c.CustmerRegion,e.EmailAddress from Customers c inner join Email e on c.ID = e.CustomerID Order by c.LastName ASC";
                _dUtil = new DataUtility("读取配置文件获取数据库连接字符串");
                _dList = new DiscountList();
                _dList.BasePrice = 35.0;
                _formatter = new DataToTextFormatter(_dUtil.GetData(sql),_dList);
    
                return _formatter.GetFormattedText();
    
            }
        }
    }
    View Code

    三、单元测试
      单元测试,引入测试框架来构建自动测试框架。

    四、控制反转(Inversion of Control,Ioc)容器,也称为依赖注入(Dependency Injection,DI)容器
         用于将对象的依赖实例传递给松散耦合类。有助于保持代码的模块性,同时自动省去需要我们手动编写的逻辑。

         让我们看一下两种不同的方法。

    using System;
    using System.Collections.Generic;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02.IoC
    {
        class ComplexObject
        {
            private ObjA _calssA;
            internal ObjA ClassA
            {
                get { return _calssA; }
                set { _calssA = value; }
            }
            private ObjB _calssB;
            internal ObjB ClassB
            {
                get { return _calssB; }
                set { _calssB = value; }
            }
            private ObjC _calssC;
            internal ObjC ClassC
            {
                get { return _calssC; }
                set { _calssC = value; }
            }
            public ComplexObject()
            {
                _calssA = new ObjA();
                _calssB = new ObjB();
                _calssC = new ObjC();
            }
    
        }
        class ObjA
        {
    
        }
        class ObjB
        {
    
        }
        class ObjC
        {
            private ObjD _calssD;
            internal ObjD ClassD
            {
                get { return _calssD; }
                set { _calssD = value; }
            }
            public ObjC()
            {
                _calssD = new ObjD();
            }
        }
        class ObjD
        {
            private int _count;
            public int Count
            {
                get { return _count; }
                set { _count = value; }
            }
        }
    }
    View Code

     最后的代码可能如下所示:
       ComplexObject obj = new ComplexObject();
       obj.ClassC.ClassD.Count=5;
       这段代码简单优美,但是违背了模块化和松散耦合的准则,使得我们不能对每个类进行测试。

     对于同样的代码,一个更清晰的版本可能如下:

    using System;
    using System.Collections.Generic;
    using System.Web;
    
    namespace ProfessionalEnterprise.Net.Chapter02.IoC
    {
        class ComplexObject
        {
            private ObjA _calssA;
            internal ObjA ClassA
            {
                get { return _calssA; }
                set { _calssA = value; }
            }
            private ObjB _calssB;
            internal ObjB ClassB
            {
                get { return _calssB; }
                set { _calssB = value; }
            }
            private ObjC _calssC;
            internal ObjC ClassC
            {
                get { return _calssC; }
                set { _calssC = value; }
            }
            public ComplexObject(ObjA a,ObjB b,ObjC c)
            {
                _calssA = a;
                _calssB = b;
                _calssC = c;
            }
    
        }
        class ObjA
        {
    
        }
        class ObjB
        {
    
        }
        class ObjC
        {
            private ObjD _calssD;
            internal ObjD ClassD
            {
                get { return _calssD; }
                set { _calssD = value; }
            }
            public ObjC(ObjD d)
            {
                _calssD = d;
            }
        }
        class ObjD
        {
            private int _count;
            public int Count
            {
                get { return _count; }
                set { _count = value; }
            }
        }
    }
    View Code

    使用时代码如下:

     ObjA A = new ObjA();  
    
     ObjB B = new ObjB();  
    
     ObjD D = new ObjD();    
    
    ObjC C = new ObjC(D);
    
    ComplexObject obj = new ComplexObject(A,B,C);
    

           在使用其他对象的类中,需要多的多的代码,而这些代码只是为了创建ComplexObject的一个实例。这正说明了松散耦合设计的好处和它的不足。松散耦合和快速开发之间的折中可以通过使用控制倒置容器来实现。Ioc容器为开发人员提供了一组在编译时对对象编译描述的全局定义。这种容器可以自动感知定义文件中的所有对象和对象依赖关系。当一个使用其他对象的方法或类需要创建复杂对象的时,这些方法和类只需要向IoC容器请求这些对象的实例,请求过程就是调用容器的get()方法,而不是常见的new操作符。下面是针对ComplexObject的IoC容器对象定义的一个示例,该示例来自于流行的Spring.NET IoC容器:

    <configuration>
      <configSections>
        <sectionGroup name="spring">
          <section name="context" type="Spring.Context.Support.ContextHandler,Spring.Core"/>
          <section name="objects" type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"/>
        </sectionGroup>
      </configSections>
      <spring>
        <context>
          <resource uri="config://spring/objects"/>
        </context>
        <objects xmlns="http://www.springframework.net">
    
        </objects>
    
      </spring>
    </configuration>

    一旦在容器中定义了对象,就可以通过容器引用来对该对象进行初始化:

    IApplicationContext Context = ContextRegistry.GetContext();
    ComplexObject obj = (ComplexObject)Context.GetObject("etlPipelineEngine");
    

      IApplicationContext是ComplexObject对象使用上下文的一种Spring.NET定义。一旦拥有了一个IApplicationContext的句柄,就可以简单的使用IApplicationContext的各种静态Get()方法通过名称来调用对象。IoC容器的好处不仅仅是对象实例化简单,还有助于开发使用对象的代码,为对象模型创建清晰的路线图,甚至提供各种层面的面向对象编程。

  • 相关阅读:
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
    第六周课程总结&试验报告(四)
    课程总结
    第十四周课程总结&实验报告(简单记事本的实现)
    第十三周
    第十二周学习总结
  • 原文地址:https://www.cnblogs.com/baoconghui/p/3086367.html
Copyright © 2020-2023  润新知