zoukankan      html  css  js  c++  java
  • LINQ to SQL活学活用(2):躲起来别让我看见

    引入

    看到上一篇的编写的测试吗?LINQ to SQL类完全暴露给了客户(这里指测试,接下来几篇将是UI表现层),客户完全操作数据(例如上一节的创建Customer),这篇我们要隐藏数据访问层的实现细节,躲起来别让我看见!

    注意:这是我第一次分析设计,我只想通过这个系列来讨论学习设计方面的东西,当然很多思想还不成熟或者有错误,只是希望通过这个系列来学习构架设计方面的东西,希望大牛们指点,大家拍砖头!

    系列文章导航

    LINQ to SQL活学活用(1):这要打破旧观念

    LINQ to SQL活学活用(2):躲起来别让我看见

    LINQ to SQL活学活用(3):嗅出“臭味”烟消云散

    LINQ to SQL活学活用(4):监视你的一举一动

    系列参考代码下载:LINQ to SQL

    改进

    这可以考虑到GoF23中的外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

    考虑在数据访问层中建立外观Facade,这样可以为复杂的数据访问方法提供一个简单的类,使得耦合大大降低。增加外观Facade可以只向客户提供一个简单的接口,减少客户与数据访问层之间的依赖,更容易维护和扩展了。

    数据访问层

    我们就使用这种方法来改进第一篇的程序吧。首先创建一个基类用于存放公共的方法,然后各个数据访问对象(这里只有Customer)继承这个基类实现具体细节。

    架构

    1.DataAccessFacadeBase基类

    使用一个公共基类,用于存放公共的方法,我们新建DataAccessFacadeBase.cs类,实例化数据访问实体DataContext,配置DataContext连接和日志。

    这里实例化数据访问实体DataContext代码同上一篇测试基类的代码相同,这里就不贴了。

    2.数据访问Facade对象

    我们为每个数据访问对象都定义一个数据访问Facade对象,用于封装一些CURD等操作,在具体数据访问类中没有Load()、Save()、Delete()方法。这样做的好处是客户使用时直接调用数据访问外观Facade里的对外提供的方法,更加基于服务,调用代码不需要担心具体的实现细节,也可很方便的对其测试。

    这里新建CustomerFacade.cs类用于封装对Customer的CURD操作,这个类继承自DataAccessFacadeBase基类,具体操作方法如下:

    1.新建临时Customer对象

    public Customer CreateCustomer()
    {
        return new Customer();
    }

    2.按CustomerId获取Customer对象

    public Customer GetCustomerById(int customerId)
    {
        return (from p in DataContext.Customer
                where p.CustomerId == customerId
                select p).FirstOrDefault();
    }

    3.获取Customer对象列表

    public IList<Customer> GetCustomerList()
    {
        return (from p in DataContext.Customer
            select p).ToList<Customer>();
    }

    4.更新保存Customer对象

    public void UpdateCustomer(Customer customer)
    {
        if (customer == null)
        {
            throw new ArgumentNullException("Customer", "对象为空");
        }
        else
        {
            if (customer.CustomerId == 0)
            {
                DataContext.Customer.InsertOnSubmit(customer);
            }
            DataContext.SubmitChanges();
        }
    }

    这里为了演示,仅仅写出了4个方法,大家可以按照自己的需要添加一些操作。

    单元测试层

    可以测试上面我们修改的结果了,在单元测试层新建一CustomerFacadeFixture.cs类依然继承测试基类UnitTestBase。

    Step1:实例化CustomerFacade

    在这个测试类中,首先实例化CustomerFacade。

    private CustomerFacade m_facade;
    public CustomerFacade Facade
    {
        get
        {
            if (m_facade == null)
            {
                m_facade = new CustomerFacade();
            }
            return m_facade;
        }
    }

    Step2:编写保存更新方法

    其次,编写一个创建并保存Customer的方法,因为我们每次测试前,数据库为空的,在测试前,我们需要输入一些原始数据。

    private Customer CreateAndSaveNewCustomer(string firstName, string lastName)
    {
        Customer newCustomer = Facade.CreateCustomer();
        newCustomer.FirstName = firstName;
        newCustomer.LastName = lastName;
        Facade.UpdateCustomer(newCustomer);
        return newCustomer;
    }

    从这个方法,我们就直接使用Facade提供给客户端的Create()方法和Update()方法,我们完全不知道具体的实现细节。

    Step3:测试UpdateCustomer()方法

    调用上面的方法,向创建保存为YJingLee的Customer为测试初始数据,正好也是测试了保存数据方法。

    [Test]
    public void UpdateCustomerTest()
    {
        Customer newCustomer = CreateAndSaveNewCustomer("YJing", "Lee");
        Assert.AreNotEqual(0, newCustomer.CustomerId);
        Assert.AreEqual("YJing", newCustomer.FirstName);
    }

    看看结果吧:

    结果

    分析一下:首先验证数据库是否存在,这里存在,删除原有的数据库重新创建一个新的数据库架构,向数据库中插入一条YJingLee的数据并查询这条数据。

    Step4:测试GetCustomerById()方法

    再来测试GetCustomerById()方法,首先在数据库中插入一条YJingLee的数据,看看这句reloaded = Facade.GetCustomerById(tempCustomer.CustomerId)调用外观Facade中的GetCustomerById()方法按CustomerId获取Customer对象,体现了对外隐藏具体的实现细节,最后断言数据是否符合预料的结果。

    [Test]
    public void GetCustomerByIdTest()
    {
        Customer tempCustomer = CreateAndSaveNewCustomer("YJing", "Lee");
        Assert.AreNotEqual(0, tempCustomer.CustomerId);
    
        Customer reloaded = Facade.GetCustomerById(tempCustomer.CustomerId);
        Assert.IsNotNull(reloaded);
        Assert.AreEqual(tempCustomer.CustomerId, reloaded.CustomerId);
        Assert.AreSame(tempCustomer, reloaded);
    }

    这个测试就留给大家测试了!测试好了把结果告诉我哦。 

    Step5:测试GetCustomerList()方法

    首先初始化三条数据,然后调用外观Facade中的GetCustomerList()方法获取Customer列表,测试是否一致

    [Test]
    public void GetListTest()
    {
        List<Customer> tempCustomers = new List<Customer>();
    
        tempCustomers.Add(CreateAndSaveNewCustomer("YJing", "Lee"));
        tempCustomers.Add(CreateAndSaveNewCustomer("li", "yongjing"));
        tempCustomers.Add(CreateAndSaveNewCustomer("cnblogs", "com"));
    
        var reloaded = Facade.GetCustomerList();
        Assert.IsNotNull(reloaded);
        Assert.AreEqual(tempCustomers.Count, reloaded.Count);
    }

    结语

    这篇文章我们通过修改第一篇完全裸露的代码,运用一个外观Facade类对外提供较清晰的接口来隐藏具体的实现细节,客户使用只需和Facade对象接口交互,从这篇的改进也完美地体现了依赖倒转原则和迪米特法则的思想。

  • 相关阅读:
    python 包管理工具 pip 的配置
    Python 变量作用域 LEGB (下)—— Enclosing function locals
    Python 变量作用域 LEGB (上)—— Local,Global,Builtin
    2020 Java 面试题 小结 (答案慢慢补上,有错误请指出)
    mysql 根据日期(date)做年,月,日分组统计查询
    jvm指令
    正则表达式 分割地址 获取省市区详细地址
    .Net 异常记录
    WCF设计服务协议(一)
    plsql ORA-01789:查询块具有不正确的结果列数
  • 原文地址:https://www.cnblogs.com/lyj/p/1329608.html
Copyright © 2011-2022 走看看