• 运用设计原则编写可测试性的代码


    初入编程开发一两个项目后,渐渐发现自己编写的代码越往后越复杂,一个类承担太多的职责每次改动都需要先理清代码逻辑,还承担着很大风险。
    接下来通过一个例子展示下这样编写可维护、可测试的代码。

    需求

    • 根据Category查询Product集合
    • 对每次查询的结果加入缓存

    不好的代码

    	public class Product
    	{
    		public int Id { get; set; }
    		public string Name { get; set; }
    		public string Category { get; set; }
    		public decimal Price { get; set; }
    	}
    
        public class ProductRepository
    	{
    		public IList<Product> GetAllProductsIn(int categoryId)
    		{
    			IList<Product> products = new List<Product>();
    			// Database operation to populate products …
    			return products;
    		}
    	}
    
        public class ProductService
    	{
    		private ProductRepository _productRepository;
    		public ProductService()
    		{
    			_productRepository = new ProductRepository();
    		}
    		public IList<Product> GetAllProductsIn(int categoryId)
    		{
    			IList<Product> products;
    			string storageKey = string.Format(“products_in_category_id_{ 0}”, categoryId);
    			products = (List<Product>)HttpContext.Current.Cache.Get(storageKey);
    			if (products == null)
    			{
    				products = _productRepository.GetAllProductsIn(categoryId);
    				HttpContext.Current.Cache.Insert(storageKey, products);
    			}
    			return products;
    		}
    	}
    

    这种编程所带来的问题

    • ProductService依赖ProductRepository类,如果ProductRepository中API修改ProductService也必须修改
    • 代码不单元测试,因ProductService依赖ProductRepository和存储HttpContext.Current.Cache
    • 如果需要利用另外的方式缓存,需要修改ProductService中方法

    健壮的代码

    • 依赖倒置原则,高层应依赖于抽象,不应依赖具体的底层。
    • 依赖注入,依赖的对象在使用时注入对象,这样可以Mock类单元测试。
        public class Product
    	{
    		public int Id { get; set; }
    		public string Name { get; set; }
    		public string Category { get; set; }
    		public decimal Price { get; set; }
    	}
    
        public interface IProductRepository
    	{
    		IList<Product> GetAllProductsIn(string categoryName);
    	}
    
        public interface ICacheStorage
    	{
    		void Remove(string key);
    		void Store(string key, object data);
    		T Retrieve<T>(string storageKey);
    	}
    
        public class ProductService
    	{
    		private IProductRepository _productRepository;
    		private ICacheStorage _cacheStorage;
    
    		public ProductService(IProductRepository productResitory, ICacheStorage cacheStorage)
    		{
    			_productRepository = productResitory;
    			_cacheStorage = cacheStorage;
    		}
    
    		public IList<Product> GetAllProductsIn(string categoryName)
    		{
    			IList<Product> products;
    
    			string storageKey = string.Format("products_in_category_id_{0}", categoryName);
    
    			products = _cacheStorage.Retrieve<IList<Product>>(storageKey);
    
    			if (products == null)
    			{
    				products = _productRepository.GetAllProductsIn(categoryName);
    				_cacheStorage.Store(storageKey, products);
    			}
    
    			return products;
    		}
    	}
    

    具体的仓储项目

    public class DataContext
    	{
    		private List<Product> _products;
    
    		public DataContext()
    		{
    			_products = new List<Product>();
    			_products.Add(new Product { Id = 1, Name = "BaseBall Cap", Price = 9.99m, Category = "Hats" });
    			_products.Add(new Product { Id = 2, Name = "Flat Cap", Price = 5.99m, Category = "Gloves" });
    			_products.Add(new Product { Id = 3, Name = "Top Hat", Price = 6.99m, Category = "Scarfs" });
    
    			_products.Add(new Product { Id = 4, Name = "Mitten", Price = 10.99m, Category = "Hats" });
    			_products.Add(new Product { Id = 5, Name = "Fingerless Glove", Price = 13.99m, Category = "Gloves" });
    			_products.Add(new Product { Id = 6, Name = "Leather Glove", Price = 7.99m, Category = "Scarfs" });
    
    			_products.Add(new Product { Id = 7, Name = "Silk Scarf", Price = 23.99m, Category = "Scarfs" });
    			_products.Add(new Product { Id = 8, Name = "Woollen", Price = 14.99m, Category = "Hats" });
    		}
    		public List<Product> Products
    		{
    			get { return _products; }
    		}
    	}
    
        public class ProductRepository:IProductRepository
    	{
    		private DataContext _dataContext;
    
    		public ProductRepository()
    		{
    			_dataContext = new DataContext();
    		}
    
    		public IList<Product> GetAllProductsIn(string categoryName)
    		{
    			var result = _dataContext.Products.FindAll(i=>i.Category == categoryName);
    			return result;
    		}
    	}
    

    单元测试

    参考下篇博客 AutoFac依赖注入应用

    下载

  • 相关阅读:
    【spring-boot】mybatis-generator 使用入门
    【spring-boot】mybatis 使用入门
    【spring-boot】logback+slf4j 日志组合
    【spring-boot】写一个简单的单元测试
    github执行clone操作时报错
    enable device: BAR 0 [mem 0x00000000-0x003fffff] not claimed
    Meson version is 0.44.1 but project requires >=0.45.
    tig
    Unknown command 'run'
    systemctl enable rc-local.service error
  • 原文地址:https://www.cnblogs.com/LoveTomato/p/9285321.html
Copyright © 2020-2023  润新知