跟着项目学设计模式(九) 装饰器模式

版权声明:本文为博主原创文章,未经博主允许不得转载。博客地址: https://blog.csdn.net/m0_37057454/article/details/82791307

接上文,既然一个服务有多个消费者,在具体的功能实现上,会遇到许多有细微差别的地方,比如:

对商品的修改有些服务需要短信通知后台管理员,有些服务需要通过邮件+站内消息的形式通知相关用户,有些服务要求无需任何通知操作。

为了能兼容这些矛盾,我们尝试去添加相应的接口如下:

public interface IOrder  
{  
    //编辑
    bool OrderEdit(Order entity);  
    //编辑附带短信
    bool OrderEditWithSMS(Order entity);
    //编辑附带站内消息和邮件
    bool OrderEditWithMESSAGE_MAIL(Order entity);
}

一旦需求有了新的变化,比如,有的服务要求编辑商品后发送站内消息+邮件,有的服务要求发送短信+站内消息+邮件等等,就需要添加新的接口。这就好像是求解一道功能之间排列组合的问题,n个功能的结果就是n的阶乘。

我们现在选择在接口设计时就把结果一一列出,声明n的阶乘个方法。一不小心就违反了单一职责原则、接口隔离原则和开闭原则。

造成这种尴尬局面的根本原因是:除了最基本的编辑之外,其他的诸如短信、邮件、站内消息等附加功能是动态的,只有在调用时,才确定具体需要哪些附加功能。

是的,这里并不需要保证数据强一致性,什么短信、邮件、站内消息都是事件驱动模型里的东西,是异步调用的,并不会阻塞订单编辑操作,正是这些并不需要事务包裹的附加功能降低了模块的内聚。

基本思路:

方案1:不改变接口,而是创建一个包装对象,也就是装饰来包裹真实的对象,动态的扩展一个对象的功能=》装饰器模式

    public interface IOrder
    {
        bool OrderEdit(Order entity);
    }

    //基本编辑功能
    public class OrderBLL : IOrder
    {}

    //短信装饰器
    public class Order_SMSDecorator : IOrder
    {}

方案2:业务逻辑层添加一个消息接口,将这些附加功能封装起来,暴露给服务端,将消息发送放到服务端去解决。

装饰器模式

装饰者模式(Decorator Pattern),是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

    public interface IOrder
    {
        bool OrderEdit(Order entity);
    }

    //基本编辑功能
    public class OrderBLL : IOrder
    {
        bool IOrderBLL.OrderEdit(Order entity)
        {
            var val = new OrderDal().OrderEdit(entity);
            return val;
        }
    }

    //短信装饰器
    public class Order_SMSDecorator : IOrder
    {
        private IOrderBLL Order;

        public Order_SMSDecorator(IOrderBLL order)
        {
            this.Order = order;
        }

        bool IOrderBLL.OrderEdit(Order entity)
        {
            var val = Order.OrderEdit(entity);
            ///////////////////
            do 发送短信
            ///////////////////
            return val;
        }
    }

    //站内消息装饰器
    public class Order_MESSAGEDecorator : IOrder
    {
        private IOrder Order;

        public Order_MESSAGEDecorator(IOrderBLL order)
        {
            this.Order = order;
        }

        bool IOrderBLL.OrderEdit(Order entity)
        {
            var val=Order.OrderEdit(entity);
            ///////////////////
            do 发送站内消息
            ///////////////////
            return val;
        }
    }

    //邮件装饰器
    public class Order_MAILDecorator : IOrder
    {
        private IOrder Order;

        public Order_MAILDecorator(IOrder order)
        {
            this.Order = order;
        }

        bool IOrderBLL.OrderEdit(Order entity)
        {
            var val = Order.OrderEdit(entity);
            ///////////////////
            do 发送邮件
            ///////////////////
            return val;
        }
    }

我们来组合出不同的功能

    var order=new OrderBLL();
    //短信
    var order_SMS=new Order_SMSDecorator(orderBLL);
    //邮件
    var order_MAIL=new Order_MAILDecorator(orderBLL);
    //邮件+站内消息
    var order_MAIL_MESSAGE=new Order_MESSAGEDecorator(order_MAIL)

好了,在最终的服务项目中调用的时候,直接在IOC里组装成不同功能的对象就可以了,这里用的是轻量级的AutoFac,可以根据name的不同获取相应的对象:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    ......
    ......

    var order=new OrderBLL();
    //短信
    var order_SMS=new Order_SMSDecorator(orderBLL);
    //邮件
    var order_MAIL=new Order_MAILDecorator(orderBLL);
    //邮件+站内消息
    var order_MAIL_MESSAGE=new Order_MESSAGEDecorator(order_MAIL)

    builder.Register(o=>order).As<IOrder>()
            .Named<IOrder>("订单").SingleInstance();

    builder.Register(o=>order_SMS).As<IOrder>()
            .Named<IOrder>("订单+短信").SingleInstance();

    builder.Register(o=>order_MAIL_MESSAGE).As<IOrder>()
            .Named<IOrder>("订单+站内消息+邮件").SingleInstance();
    ......
    ......
}

 

猜你喜欢

转载自blog.csdn.net/m0_37057454/article/details/82791307