zoukankan      html  css  js  c++  java
  • [Architecture Pattern] Lazy Decoration

    动机 :

    在设计面向对象应用程序架构的时候,
    对象会包含相关的企业逻辑,而不是单纯的数据对象。
    但是当企业逻辑需要取得其他对象一起运算,如何「取得」是一件很复杂的事情。

    例如说:
    在系统内有一个「查询客户订单总金额」的企业逻辑,需要从系统取出客户的所有订单做金额加总。
    这个企业逻辑实作上可以分配到不同的对象,这边我们先定义这个企业逻辑是客户对象的职责。
    并用下列的程序代码,实作这个企业逻辑,
    这样的范例是可以正常的工作。

    但是换个场景会发现,在只是要编辑客户电话的时候,也需要取得订单查询接口。
    当系统越来越庞大,企业逻辑越来越多时,这个范例架构就会显得是个灾难。
    而且再细看的话会发现订单有参考到客户,这个范例有循环相依的问题。

    namespace ConsoleApplication001
    {
        public class Customer
        {
            public Guid Id { get; private set; }
    
            public string Name { get; set; }
    
            private readonly IOrderRepository _orderRepository = null;
    
            
            public Customer(Guid id, IOrderRepository orderRepository)
            {
                this.Id = id;
                this.Name = string.Empty;
                _orderRepository = orderRepository;
            }
    
    
            public int GetTotal()
            {
                int total = 0;
                foreach (Order order in _orderRepository.GetListByCustomer(this))
                {
                    total += order.Price;
                }
                return total;
            }
        }
    
        public class Order
        {
            public Guid Id { get; private set; }
    
            public Customer Customer { get; private set; }
    
            public int Price { get; set; }
    
    
            public Order(Guid id, Customer customer)
            {
                this.Id = id;
                this.Customer = customer;
                this.Price = 0;
            }
        }
    
        public interface IOrderRepository
        {
            IEnumerable<Order> GetListByCustomer(Customer customer);
        }
    }

    将系统重写成下列的程序代码,改由运作时将订单查询接口注入。
    这样的范例也是可以正常的工作,但是依然没有解决循环相依的问题。

    namespace ConsoleApplication002
    {
        public class Customer
        {
            public Guid Id { get; private set; }
    
            public string Name { get; set; }
    
    
            public Customer(Guid id)
            {
                this.Id = id;
                this.Name = string.Empty;
            }
    
    
            public int GetTotal(IOrderRepository orderRepository)
            {
                int total = 0;
                foreach (Order order in orderRepository.GetListByCustomer(this))
                {
                    total += order.Price;
                }
                return total;
            }
        }
    
        public class Order
        {
            public Guid Id { get; private set; }
    
            public Customer Customer { get; private set; }
    
            public int Price { get; set; }
    
    
            public Order(Guid id, Customer customer)
            {
                this.Id = id;
                this.Customer = customer;
                this.Price = 0;
            }
        }
    
        public interface IOrderRepository
        {
            IEnumerable<Order> GetListByCustomer(Customer customer);
        }
    }

    本文介绍一个『Lazy Decoration模式』。
    定义对象的职责跟规则,将对象与对象之间的相依性做切割。
    用来解决上列描述的问题。

    结构 :

    下图是这个架构的示意图。
    可以看到除了系统原本就有的客户、订单、订单查询接口之外,多了两个客户实体、客户实体工厂对象。

    订单到客户之间的相依,透过客户实体、客户实体工厂做了相依性切割。
    并且将「查询客户订单总金额」的企业逻辑,改分派到(客户实体)上。
    需要做「查询客户订单总金额」时,再建立(客户实体)来查询。
    而(客户实体)因为是继承自(客户)对象,在后续的应用,也可以直接将它当作(客户)来用。

    image

    实作 :

    文字写起来很复杂,其实看程序代码很简单。
    首先定义基本的(客户)、(订单)、(订单查询接口)这三个对象。
    要特别注意的是(客户)对象,它除了基本的建构函式之外,还包含了一个将自己当作参数的建构函式。
    这让继承的对象,不用关注属性增加、属性更名、属性值初始化...等等工作。

    namespace ConsoleApplication003
    {
        public class Customer
        {
            public Guid Id { get; private set; }
    
            public string Name { get; set; }
    
    
            public Customer(Guid id)
            {
                this.Id = id;
                this.Name = string.Empty;
            }
    
            public Customer(Customer item)
            {
                this.Id = item.Id;
                this.Name = item.Name;
            }
        }
    
        public class Order
        {
            public Guid Id { get; private set; }
    
            public Customer Customer { get; private set; }       
    
            public int Price { get; set; }        
    
    
            public Order(Guid id, Customer customer)
            {
                this.Id = id;
                this.Customer = customer;            
                this.Price = 0;
            }
        }
    
        public interface IOrderRepository
        {
            IEnumerable<Order> GetListByCustomer(Customer customer);
        }
    }

    再来看看(客户实体)对象,
    它继承了(客户)对象,并且实作了「查询客户订单总金额」这个企业逻辑。

    namespace ConsoleApplication003
    {
        public class CustomerEntity : Customer
        {
            private readonly IOrderRepository _orderRepository = null;
    
    
            public CustomerEntity(Customer item, IOrderRepository orderRepository)
                : base(item)
            {
                _orderRepository = orderRepository;
            }
    
            public int GetTotal()
            {
                int total = 0;
                foreach (Order order in _orderRepository.GetListByCustomer(this))
                {
                    total += order.Price;
                }
                return total;
            }
        }
    }

    最后是(客户实体工厂),
    它很简单的只是在建立(客户实体)时,将(订单查询接口)对象做注入的动作。

    namespace ConsoleApplication003
    {
        public class CustomerEntityFactory
        {
            private readonly IOrderRepository _orderRepository = null;
    
    
            public CustomerEntityFactory(IOrderRepository orderRepository)
            {
                _orderRepository = orderRepository;
            }
    
    
            public CustomerEntity Create(Customer item)
            {
                return new CustomerEntity(item, _orderRepository);
            }
        }
    }

    在这些对象整个建立完毕之后,
    当我们要做客户数据的新增、修改、删除、查询,直接将(客户)对象进出 Data Access Layer(DAL)。

    namespace ConsoleApplication003
    {
        class Test001
        {
            static void MainXXX(string[] args)
            {
                ICustomerRepository customerRepository = null; // 使用例如Spring.Net、Provider Pattern来反射生成。 
    
                foreach (Customer customer in customerRepository.GetAll())
                {
                    Console.WriteLine(customer.Name);
                }
            }
        }        
    }
    
    namespace ConsoleApplication003
    {
        public interface ICustomerRepository // Customer的DAL界面
        {
            Customer[] GetAll();
    
            Customer GetById(Guid id);
        }
    }

    当要查询某个客户的订单总金额时,建立(客户实体)就可以做查询。

    namespace ConsoleApplication003
    {
        class Test002
        {
            static void MainXXX(string[] args)
            {
                ICustomerRepository customerRepository = null; // 使用例如Spring.Net、Provider Pattern来反射生成。 
                IOrderRepository orderRepository = null;// 使用例如Spring.Net、Provider Pattern来反射生成。             
                CustomerEntityFactory customerEntityFactory = new CustomerEntityFactory(orderRepository);
    
                Customer customer = customerRepository.GetById(Guid.Parse("xxxxx"));
                CustomerEntity customerEntity = customerEntityFactory.Create(customer);
    
                Console.WriteLine(customerEntity.GetTotal());
            }
        }
    }
    
    namespace ConsoleApplication003
    {
        public interface ICustomerRepository // Customer的DAL界面
        {
            Customer[] GetAll();
    
            Customer GetById(Guid id);
        }
    }

    后记 :

    这个模式除了范例示范的企业逻辑分派为对象方法之外,也可以延伸成为对象属性、对象事件等等的功能。
    在实作的时候这个模式,也能将不同的企业逻辑做分类。例如 : CustomerQueryEntity、CustomerVerifyEntity。

    最后一提的是,这个模式是从 [Application Architecture] : Lazy Boundary 模式 所重整提取出来。
    当我们,
    将在开发软件项目的时候,遇到的各种不同功能面对象,归类并取一个好记的名字。
    反复重整功能面对象跟名词,最终就会产生属于自己的模式。 :D

  • 相关阅读:
    HDU5418.Victor and World(状压DP)
    POJ2686 Traveling by Stagecoach(状压DP)
    POJ3254Corn Fields(状压DP)
    HDU5407.CRB and Candies(数论)
    CodeForces 352D. Jeff and Furik
    CodeForces 352C. Jeff and Rounding(贪心)
    LightOj 1282 Leading and Trailing
    Ural 1057. Amount of Degrees(数位DP)
    HDU 2089 不要62 (数位DP)
    HDU5366 The mook jong (DP)
  • 原文地址:https://www.cnblogs.com/clark159/p/2205163.html
Copyright © 2011-2022 走看看