《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战

发布时间:2020-05-12 01:00:50 作者:yanyangtian
来源:网络 阅读:912
2.1.2  设计原则实战
 
    下面我们就以一个简单的电子商务系统为背景:通过给定的产品分类ID获取该分类下的所有产品。
对于这个问题,基本上不用想就可以实现,如图2-1的类图设计。
 
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
 
2-1  获取分类产品的类图
 
其中:
q  ProductService类被客户程序调用,通过调用GetAllProductsFrom方法来获取产品,并且此处还可以添加缓存策略或异常处理等机制。
 
q  Product类代表了产品的实体。
 
q  ProductRepository类用来从数据存储设备(数据库或XML等其他数据存储器)中读取产品信息。     
 
注意  为了减少读者不必要的麻烦,让理解更加直观,以后的章节中,都会给出完整的代码示例和项目图示。
在这个示例中,Visual Studio项目的结构图如图2-2所示。
 
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
2-2  Visual Studio解决方案图
 
 
    正如之前所说:ProductService提供外部调用的方法接口,并且采用了缓存策略和异常处理机制,来提高程序的性能和健壮性,代码如下所示:
 
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using System;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 usingSystem.Collections.Generic;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 usingSystem.Web;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using AgileSharp.Chapter2.Repository;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using AgileSharp.Chapter2.Domain;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 namespace AgileSharp.Chapter2.Service
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public class ProductService
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         private ProductRepository productRepository = null;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public ProductService()
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 productRepository = new ProductRepository();
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public List<Product> GetAllProductsFrom(intcategoryId)
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         List<Product> result = new List<Product>();
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 try
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                                 string cacheKey = string.Format("products_in_category_{0}",categoryId);
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 result = HttpContext.Current.Cache.Get(cacheKey) as List<Product>;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 if (result == null)
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                                 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         result = productRepository.GetProductsFrom(categoryId);
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         if (result != null &&result.Count> 0)
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                                             {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         HttpContext.Current.Cache.Insert(cacheKey, result);
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                                             }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                                 }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 catch (Exception ex)
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                                 //Log will add here later
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                         }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 return result;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 }
 
    至于ProductProductRepository的代码就非常简单了,这里不多解释。
 
示例到这里,也许大家有个疑问:上面的代码有些什么问题?
 
q  ProductService依赖于ProductRepository。在没有任何变化的情况下,这没有什么问题。但是如果现在项目换了数据存储设备,例如将数据库换成了XML文件,或者数据库的访问技术从ADO.NET 换成了Entity Framework,那么ProductRepository的代码就得改变,这会使得整个项目都需要重新编译,重新部署。问题来了:此时系统中只有ProductRepository一个变化点,为什么非得要求整个项目重新编译,重新部署呢?难道不能只重新编译和部署那个变化的模块呢?
 
q  代码不具有测试性能。要想知道此段功能代码是否按照了我们的意愿运行,可以通过人工审核,然后通过GUI界面获取数据来进行调试,此时的逻辑相对而言比较简单,此方法也还行得通。不过,一旦业务逻辑变得复杂或代码量的剧增,那么很难确保代码不会出错,而这些错误很多时候只会在运行时才能被发现。
 
q  缓存机制依赖于HttpContext,这不仅仅会让测试产生困难(尽管可以有Mock),而且会对后续系统的扩展有阻碍(例如采用分布式缓存)。
 
对以上的问题进行进一步分析,可以知道,这都是因为违背了以下设计原则:
 
q  ProductService依赖了ProductRepository的具体实现,而ProductRepository是一个可能的变化点。也就是说:ProductService这个高层模块依赖了ProductRepository底层模块,违背了依赖倒置原则,这也就使得一个ProductRepository变化,整个项目都需要重新编译,重新部署。同理,缓存机制也是。
 
q  对于可测试性的问题,严格来说,上面的代码是可以测试的,但是测试的时候必须依赖于外部的数据存储设备,例如数据库,那么测试的结果可能会由于数据的变动而不一样,而且每次测试所花的时间也会比较长。
 
接下来尝试重构上面的代码,让代码的组织方式更加的灵活和易于扩展。
 
    既然上面代码主要是违背了DIP依赖倒置原则(再次回顾一下DIP:依赖抽象,而不依赖具体实现)。
 
    那么现在就提出接口IProductRepository,使得ProductService依赖这个接口,代码如下:
 
 
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using System.Collections.Generic;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using AgileSharp.Chapter2.Domain;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 namespace AgileSharp.Chapter2.Repository
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public interface IProductRepository
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 List<Product> GetProductsFrom(intcategoryId);    
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 }
   
    现在接口已经抽象出来了,ProductService可以直接依赖接口了,但是我们现在还需要一个实现IProductRepository接口的类ProductRepository,然后再采用LSP(里氏替换原则),用ProductRepository替换。代码如下:
 
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using System;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 usingSystem.Collections.Generic;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using AgileSharp.Chapter2.Domain;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 namespace AgileSharp.Chapter2.Repository
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public class ProductRepository:IProductRepository
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战          //…
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 }
    现在ProductService的代码如下所示:
 
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using System;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 usingSystem.Collections.Generic;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 usingSystem.Web;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using AgileSharp.Chapter2.Repository;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 using AgileSharp.Chapter2.Domain;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 namespace AgileSharp.Chapter2.Service
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public class ProductService
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         privateIProductRepositoryproductRepository = null;
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         publicProductService()
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 productRepository = new ProductRepository();
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                 }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         public List<Product> GetAllProductsFrom(intcategoryId)
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战              {
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战                      //...
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战              }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战         }
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战
《.NET应用架构设计:原则、模式与实践》新书博客--试读-2.1.2 设计原则实战 }
    其实可以看到,上面ProductService的代码虽然提出了抽象接口,但问题依然存在:仍依赖于ProductRepository的具体实现。
 
    问题到这里就好办了,可以采用工厂模式,通过读取配置文件进行反射或采用依赖注入等方法得到解耦。
 
    可以看出:设计原则解决了变化点的问题,将ProductRepository这个变化点从ProductService中移出,然后一步步的迁移,最后把这个变化点引到了配置文件中,也就是将变化点引到了系统之外,也许这些正是我们需要的。
 
    当当网:http://product.dangdang.com/product.aspx?product_id=22574513
    京东地址:http://book.360buy.com/10893935.html
    卓越地址:http://www.amazon.cn/mn/dp/B006NS2N0S
推荐阅读:
  1. 索引设计原则
  2. OO设计原则

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

职场 休闲 《.net应用架构设计:原则、模式与实践

上一篇:用敏捷玩转软件开发 - 序

下一篇:Python的"print"函数在“Hello World”之外的延伸

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》