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


    引入

    再次想想上一篇的设计,在第一篇中我说过这个系列的目标是构建一个N层程序,要求这个程序可测试、可维护、可复用、可扩展。我们做到了吗?

    可测试:恩,现在可以测试!并且隐藏了具体细节,这个比较满意!

    可维护:好像现在没有什么维护的,不就是这点功能吗?

    可复用:这点功能叫我怎么复用?我另外写一个程序或许比这个更好呢?

    可扩展:恩,需要多多扩展,就这点功能!

    好!我就想扩展了!就想开始了!却......不好扩展啊,我们看看上一篇的不足点,虽然我们把所有的数据库操作都封装起来了。但是没有做到彻底的隔离。因为客户端直接使用了Customer这个类。 而这个类是和LINQ to SQL实现捆绑在一起的。所以客户端还是知道你在使用LINQ to SQL,用这种方式依赖还是传递的,使用接口方式可以倒置依赖关系从而完全解除对LINQ to SQL的依赖。感谢朱良雄和possible两位朋友对上篇文章的点评,一针见血!

    这就是当前程序嗅出的“臭味”,我们有什么办法呢?如何避免呢?这篇我们还是讨论这个问题吧!

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

    系列文章导航

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

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

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

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

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

    改进

    知道程序的“臭味”,我们如何改进呢?想想,通过接口隐藏实体。我们利用接口实现,为Customer创建分部类,创建ICustomer接口,Customer实现ICustomer接口,利用ICustomer接口编写CustomerFacade,根据新的ICustomer接口更新单元测试,而不是上一节的对Customer对象做单元测试,这样客户就不知道数据访问层中具体实现了。这就是我们这一节做的工作。

    数据访问层

    进一步改进我们的程序,看看数据访问层的类图设计:

    架构

    1.新建ICustomer接口

    public interface ICustomer
    {
        int CustomerId { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }

    2.新建分部类Customer实现ICustomer接口

    public partial class Customer : ICustomer
    {
    
    }

    我在这里这个分部类就空实现了,实际上是数据访问对象DataContext中的Customer类(数据访问对象)实现了这个接口。

    3.修改数据访问外观基类

    增加一个方法实现IQueryable<T>转换为IList<TInterface>接口

    protected IList<TInterface> ConvertToList<TInterface, TConcrete>(
        IEnumerable<TConcrete> convertThis)
        where TConcrete : TInterface
    {
        if (convertThis == null)
        {
            return new List<TInterface>();
        }
        else
        {
            IList<TInterface> returnValue = new List<TInterface>();
            foreach (TConcrete item in convertThis)
            {
                returnValue.Add(item);
            }
            return returnValue;
        }
    }

    4.修改数据访问外观CustomerFacade

    这个类中封装了Customer对象的具体CRUD实现,我们需要修改,实现接口。

    Step1:新建临时Customer对象

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

    Step2:按CustomerId获取Customer对象

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

    Step3:获取Customer对象列表

    public IList<ICustomer> GetCustomerList()
    {
        IQueryable<Customer> results =
            from p in DataContext.Customer
            select p;
        return ConvertToList<ICustomer, Customer>(results);
    }

    Step4:更新保存Customer对象

    public void UpdateCustomer(ICustomer customer)
    {
        Customer tempCustomer = customer as Customer;
        if (tempCustomer.CustomerId == 0)
        {
            DataContext.Customer.InsertOnSubmit(tempCustomer);
        }
        DataContext.SubmitChanges();
    }

    数据访问层修改完毕了。

    单元测试层

    只要把相应的数据访问对象换为数据访问对象接口,可以倒置依赖关系从而完全解除对LINQ to SQL的依赖。

    Step1:修改创建并保存Customer方法:

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

    Step2:修改测试UpdateCustomer()方法:

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

    Step3:修改GetCustomerByIdTest()方法:

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

    这篇公布一下这个测试方法结果吧:

    测试

    Step4:修改获取Customer列表方法

    [Test]
    public void GetListTest()
    {
        List<ICustomer> tempCustomers = new List<ICustomer>();
        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);
    }

    结语

    通过这篇的修改,我们程序的“臭味”基本上没有了,依赖关系从原来的对LINQ to SQL的依赖转为接口,客户直接使用接口。下篇就开始扩展吧,看看LINQ to SQL还有什么好东西!

  • 相关阅读:
    关于Ajax中this失效
    添加时间周期一年半年季度
    回车事件
    alt与title
    关于checked="checked"却不显示选中的“对勾”
    正则表达式的使用
    关于JQ 查找不到对象的clientHeight,
    Mysql笔记之 -- 开启Mysql慢查询
    Mysql笔记之 -- 小试MYSQL主从配置
    Linux系统学习笔记之 1 一个简单的shell程序
  • 原文地址:https://www.cnblogs.com/lyj/p/1330062.html
Copyright © 2020-2023  润新知