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 receivers;]
邮箱模块,发送邮件,类描述略..
2.问题描述:
写日志的话,new SysLog().handle();
短消息的话,new WeChat().handle();
邮件的话,new Mail().handle();
如果有一个需求,把某条消息Message,既写日志又发邮件还发站内短消息。岂不是得分别生成这三个对象,再分别调用handle()方法?
有没有一种好的设计,能够实现在代码中只需类似
new Message().logHandle().WeChatHandle().MailHandle();
你的描述看的不是太清晰,说下自己做过类似的案例:
一个监控的应用,主要监控集群实例状态、主机运行情况等等,预先设置阀值,如果低于阀值,就执行相应的告警处理,如:实例的内存、队列低于阀值,就执行日志处理,如实例挂掉,就执行日志处理、短信通知……
其实就是对获取到的监控数据分析之后,通过监听器进行处理。如:
定义接口Listener,方法doHandle()
定义几种实现类(LogListener、MessageListener、MailListener……)
对于你说的消息,可以在获取消息的类中添加实例变量listeners集合,把几种listener实现类注入到这个集合里面,那么对于消息的后续处理可通过:
for(Listener listener: listeners) {
listener.doHandle(message);
}
这样可以做到实际处理类与消息的低耦合,如果后面又增加一种监听器,这里的代码不用改,只需要注入新的监听器即可。
写日志、发短消息、发邮件等其实都是做同一类事情,也就是对事件进行记录或是通知,提供一个专门的【事件处理服务】,使用者只需要调用这个【事件处理服务】就行了,而这个【事件处理服务】内部会进行写日志、发短消息、发邮件或是几种的组合操作。也即是说把业务层和写日志发消息发邮件的这个层进行的分离,降低了耦合,也减少了重复代码,业务层只需要认识这个【事件处理服务】就行了,也就封装了变化。
另外,这根本不是系统设计,只是代码实现层次的设计。
设计模式的组合模式。
建个CompositeHandler类,它本身实现handle,在类里面有个实现handle的类的列表。
然后,
即可。
这个地方适当的使用装饰器模式可能比较适合:
(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信息,就修改相应的构造函数
什么模式也不用 简单的包装一下就行了
[code="java"]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;
}
}[/code]
调用
[code="java"]new Message().logHandle().WeChatHandle().MailHandle(); [/code]
当然Message可以做成单例
[code="java"]Message.getInst().logHandle().WeChatHandle().MailHandle(); [/code]
:oops: :oops: :oops:
你是需要根据Logger级别来做不同的处理的一个帮助类吧?
出现Exception可能需要三个都掉用, 出现warn的时候可能只需要Wechat?
写个静态类实现下不就成了? 那种return this的思路不对, 万一哪天需要修改下策略, 所有调用的地方都得修改...
Log.AppException(******); -- 三个都调用, 下次exception策略修改的时候 只需要修改这里。
Log.Warn(); --这里可能只需要调用两个
不要为了缩短一行代码掉坑里了.
那就参考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;
}
}
}
这样就做到处理的对象和处理类之间的解耦,每个处理类只处理自己支持的类型。不知道是否能满足你的设计需求