Java监听器实现

时间:2018-02-13 04:47:15

标签: java oop design-patterns

为以下用例寻找最佳设计。

使用案例 在我的应用程序中,我每隔一小时运行一次调度程序并公开服务。

调度程序每隔一小时运行一次并从特定表中检索记录,并在任何记录处理失败时发送通知。通知可以是电子邮件或短信。

此外,其他服务可以调用此服务进行记录处理失败通知(电子邮件或短信)。

失败类型将是batchFailure或serviceFailure。

此外,还有一些道具设置类可启用或禁用SMS&电子邮件通知。

public class Settings {
  private boolean emailEnabled;
  private boolean smsEnabled;
}

电子邮件主题应包含主题为"批次失败"或者"服务失败"根据类型。批处理作业和服务失败的其他内容保持不变。

我创建了以下类: -

  1. 主题 - 我为两者创建了一个共同主题。

    public class Notification {
    
          private int recordId;
    
          private String recordName;
    
          private String email;  // Related to email
    
          private String smsNumber; // Related to sms
    
    }
    
  2. 监听器类

    public interface RecordFailureListener {
    
      void sendNotification(Notification notification);
    
    }
    
  3. EmailListener

    public class EmailListener implements RecordFailureListener {
    
       void sendNotification(Notification notification) {
        // Code to send email here
       }
    }
    
  4. SMSListener

    public class SMSListener implements RecordFailureListener {
    
       void sendNotification(Notification notification) {
        // Code to send SMS here
       }
    }
    
  5. 服务类

    public class NotificationService {
       List<RecordFailureListener> listeners = new ArrayList(); // This list has emailListener and smsListener
    
       void sendNotification(Notification notification) {
           listeners.forEach(listener -> listener.sendNotification(notification));
       }
    }
    
  6. 如果发生任何故障,将从调度程序调用此通知服务。此外,从故障服务曝光。

    问题:

    1)在这里,主题似乎具有电子邮件和短信所需的属性。还有其他更好的方法,以便电子邮件通知将具有电子邮件和短信通知所需的属性将具有短信所需的属性?并且还有一些共同的属性。

    2)在调用发送电子邮件之前检查电子邮件侦听器中是否已启用电子邮件,并且在sms侦听器中也是如此。这是对的吗?

    还有其他更好的设计吗?

    由于

2 个答案:

答案 0 :(得分:1)

你的问题是经典的通知/听众问题。 我建议使用事件总线,作为解除lisetner和通知器的手段。这个想法是通知程序将通知事件总线,事件总线将通过监听器并在通知时更新它们。设计如下: (这是一个裸露的骨架,有一些方便的快捷方式,例如使用事件布的枚举单例。详细信息取决于你。)

public interface Event {
    // general event information - date, message, meta data, etc....
}
public interface Listener { 
   public void listen(Event event);
}

public enum EventBus {
   INSTANCE;

   private List<Listener> listeners = new ArrayList<>;

   public void addListener(Listener newListener) {
       listeners.add(newListener);
   }

   public void notify(Event event) {
      for (Listener listener : listeners) {
         listener.listen(event);
      }
   }
}


public class Notifier {

    public void handlePointOfInterest(.....) {
        // do something interesting with the parameters, etc...
        Event event = // create a new event based on your needs
        EventBus.INSTANCE.notify(event);
        ...
    }
}

您的事件界面也可以使用泛型来支持特定的元数据类型 - 例如您的设置。 您的侦听器实现可以使用泛型来处理特定类型的事件。

希望这有帮助,请随时要求澄清。

答案 1 :(得分:0)

只分享我的设计模式,尽管还有一个小问题。

可以在NotificationService本身中验证设置,因为这是我们开始通知流程的地方。假设正在从Scheduler调用NotificationService进行故障通知

public class NotificationService {

    Notification notification;

   static List<RecordFailureListener> listenerList = new ArrayList<>(); // holds email & sms listeners

    public NotificationService (Notification notification){
        this.notification=notification;
    }

    public void sendNotification(){

        if(Settings.emailEnabled){
            listenerList.stream().filter(i-> i instanceof EmailListener).forEach(i->i.sendNotification(notification));
        }
        if(Settings.smsEnabled){
            listenerList.stream().filter(i-> i instanceof SmsListener).forEach(i->i.sendNotification(notification));
        }

    }
}

RecordeFailureListener

public interface RecordFailureListener {

    void sendNotification(Notification notification);
}

EmailListener(FailureType可以在此处验证以为电子邮件分配相应的主题行)

public class EmailListener implements RecordFailureListener {

    private String emailSubject;//emailistener specific property
    @Override
    public void sendNotification(Notification notification) {

        if(Stream.of("BatchFailure","ServiceFailure").anyMatch(notification.getFailureType()::equalsIgnoreCase)){
            emailSubject= notification.getFailureType();
        }
        else{
            emailSubject="customSubject";
        }

        //code to send email notification

    }
}

SMSListener

public class SmsListener implements  RecordFailureListener {
    @Override
    public void sendNotification(Notification notification) {
        //code to sms notification
    }
}

设置

public class Settings {

     public static boolean emailEnabled;
     public static boolean smsEnabled;
}

通知模型(已添加failureType作为Notification属性)

 public class Notification {

    private int recordId;
    private String recordName;
    private String email;
    private String smsnumber;
    private String failureType;
}