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

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

需求

  • 根据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依赖注入应用

下载

转载于:https://www.cnblogs.com/LoveTomato/p/9285321.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值