问题描述
1.场景描述: 我们有信息处理子系统,包含的抽象类如下: Message[抽象类,string info;void handle();] Log[抽象类,string serviceName;string methodName;] 日志模块,包含的类如下: SysLog[系统日志,Exception exp;void handle(){Log.append(info,exp);}] Business[业务日志] 站内短消息模块,包含的类如下: WeChat[短消息,string title,User sender;List<User> receivers;] 邮箱模块,发送邮件,类描述略..2.问题描述: 写日志的话,new SysLog().handle(); 短消息的话,new WeChat().handle(); 邮件的话,new Mail().handle(); 如果有一个需求,把某条消息Message,既写日志又发邮件还发站内短消息。岂不是得分别生成这三个对象,再分别调用handle()方法? 有没有一种好的设计,能够实现在代码中只需类似new Message().logHandle().WeChatHandle().MailHandle(); 问题补充:可能是代码太简陋的,有些奇异,补充一下:之所以现在需要构造每一种(SysLog、WeChat、Mail)对象,然后分别处理,是因为三者的构造函数所需要的参数是不同的。例如:SysLog可能封装Exception等;WeChat可能需要封装Sender信息等;Mail可能需要封装Sender、Receiver等信息。否则的话,用大家的处理方式都是行的通的。也就是说,消息(Message)的生成者(业务代码)需要对不同的消息处理者(SysLog、WeChat、Mail)进行一定的干预。按照目前的情况,生产一条消息(Message),需要分别包装成SysLog、WeChat、Mail,然后调用各自的handle();方法进行处理。因此,我们现在寻求一种把消息(Message)和消息处理SysLog、WeChat、Mail进行解耦的合理方案。
解决方案
你的描述看的不是太清晰,说下自己做过类似的案例:一个监控的应用,主要监控集群实例状态、主机运行情况等等,预先设置阀值,如果低于阀值,就执行相应的告警处理,如:实例的内存、队列低于阀值,就执行日志处理,如实例挂掉,就执行日志处理、短信通知……其实就是对获取到的监控数据分析之后,通过监听器进行处理。如:定义接口Listener,方法doHandle()定义几种实现类(LogListener、MessageListener、MailListener……)对于你说的消息,可以在获取消息的类中添加实例变量listeners集合,把几种listener实现类注入到这个集合里面,那么对于消息的后续处理可通过:for(Listener listener: listeners) { listener.doHandle(message);}这样可以做到实际处理类与消息的低耦合,如果后面又增加一种监听器,这里的代码不用改,只需要注入新的监听器即可。
解决方案二:
那就参考spring security的拦截器案例来实现,每个拦截器先检查是否是自己需要的类,如果不是,跳过,如果是,自己处理。也就是在Listener接口与实现类之间再抽象出一层,增加一个抽象方法isSupport(Object object),并且实现doHandle方法,如下:public abstract class AbstractListener implements Listener { public void doHandle(Object object) { if(isSupport(object)) { handle(object) } } protected abstract void handle(Object o); protected abstract boolean isSupport(Object o);}具体实现类:public class SysLog extends AbstractListener { protected void handle(Object o) { 业务逻辑处理 } protected boolean isSupport(Object o) { if(o == null) return false; if(o instanceof Exception) { return true; } }}这样就做到处理的对象和处理类之间的解耦,每个处理类只处理自己支持的类型。不知道是否能满足你的设计需求
解决方案三:
你是需要根据Logger级别来做不同的处理的一个帮助类吧?出现Exception可能需要三个都掉用, 出现warn的时候可能只需要Wechat?写个静态类实现下不就成了? 那种return this的思路不对, 万一哪天需要修改下策略, 所有调用的地方都得修改...Log.AppException(******); -- 三个都调用, 下次exception策略修改的时候 只需要修改这里。Log.Warn(); --这里可能只需要调用两个不要为了缩短一行代码掉坑里了.
解决方案四:
什么模式也不用 简单的包装一下就行了class Message{ SysLog sysLog = new SysLog(); WeChat chat = new WeChat(); Mail mail = new Mail(); public Log logHandle(){ sysLog.handle(); return this; } public Log WeChatHandle(){ chat.handle(); return this; } public Log MailHandle(){ mail.handle(); return this; }}调用new Message().logHandle().WeChatHandle().MailHandle(); 当然Message可以做成单例 Message.getInst().logHandle().WeChatHandle().MailHandle();
解决方案五:
这个地方适当的使用装饰器模式可能比较适合:(1)Message:public abstract class Message {abstract void handle(String info);}(2)Mail: public class Mail extends Message{private Message message;public Mail(){}public Mail(Message message){this.message = message;}void handle(String info) {System.out.println("mail:"+info);//Mail的handle逻辑,此处简化为打印if(message != null){message.handle(info);}}}(3)SysLog:public class SysLog extends Message{private Message message;public SysLog(){}public SysLog(Message message){this.message = message;}void handle(String info) {System.out.println("syslog:"+info);//SysLog的handle逻辑,此处简化为打印if(message != null){message.handle(info);}}}(4)main:new Mail(new SysLog()).handle("ok");//注:可以以任意组合和顺序来装饰不知道是否满足你的场景?如果需要receivers信息,就修改相应的构造函数
解决方案六:
设计模式的组合模式。建个CompositeHandler类,它本身实现handle,在类里面有个实现handle的类的列表。然后,1. 按需求组合构建CompositeHandler。add需要的实例进去,比如Message,WeChat等。2. 调用CompositeHandler的handle方法,该方法中循环上述的list,分别调用它们的handle方法。即可。
解决方案七:
写日志、发短消息、发邮件等其实都是做同一类事情,也就是对事件进行记录或是通知,提供一个专门的【事件处理服务】,使用者只需要调用这个【事件处理服务】就行了,而这个【事件处理服务】内部会进行写日志、发短消息、发邮件或是几种的组合操作。也即是说把业务层和写日志发消息发邮件的这个层进行的分离,降低了耦合,也减少了重复代码,业务层只需要认识这个【事件处理服务】就行了,也就封装了变化。另外,这根本不是系统设计,只是代码实现层次的设计。
解决方案八:
1. 如果觉得每次new不优雅,那就将这三个类做成单例,只要业务允许2. 如果要做成链式的,在Message里定义你这三个方法 *Handle(),返回值为Message。