接上文,既然一个服务有多个消费者,在具体的功能实现上,会遇到许多有细微差别的地方,比如:
对商品的修改有些服务需要短信通知后台管理员,有些服务需要通过邮件+站内消息的形式通知相关用户,有些服务要求无需任何通知操作。
为了能兼容这些矛盾,我们尝试去添加相应的接口如下:
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();
......
......
}