行为型模式:20-观察者模式
2021-06-20 本文已影响0人
综合楼
观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,
使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器
(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

在观察者模式结构图中包含如下几个角色:
● Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集
合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察
者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
● ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数
据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义
的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接
口声明了更新数据的方法update(),因此又称为抽象观察者。
● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它
存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观
察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自
己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
代码示例:
import java.util.ArrayList;
public abstract class MySubject {
protected ArrayList observers = new ArrayList();
//注册方法
public void attach(MyObserver observer) {
observers.add(observer);
}
//注销方法
public void detach(MyObserver observer) {
observers.remove(observer);
}
public abstract void cry(); //抽象通知方法
}
public interface MyObserver {
void response(); //抽象响应方法
}
------------------------------------------------------
public class Cat extends MySubject {
public void cry() {
System.out.println("猫叫!");
System.out.println("----------------------------");
for (Object obs : observers) {
((MyObserver) obs).response();
}
}
}
------------------------------------------------------
public class Dog implements MyObserver {
public void response() {
System.out.println("狗跟着叫!");
}
}
------------------------------------------------------
public class Mouse implements MyObserver {
public void response() {
System.out.println("老鼠努力逃跑!");
}
}
------------------------------------------------------
public class Pig implements MyObserver {
public void response() {
System.out.println("猪没有反应!");
}
}
public class Client {
public static void main(String a[]) {
MySubject subject = new Cat();
MyObserver obs1, obs2, obs3;
obs1 = new Mouse() ;
obs2 = new Mouse();
obs3 = new Dog();
subject.attach(obs1);
subject.attach(obs2);
subject.attach(obs3);
MyObserver obs4;
obs4 = new Pig();
subject.attach(obs4);
subject.cry();
}
}

JDK对观察者模式的支持

自定义登录组件

import java.util.EventObject;
public class LoginEvent extends EventObject {
private String userName;
private String password;
public LoginEvent(Object source, String userName, String password) {
super(source);
this.userName = userName;
this.password = password;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return this.userName;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return this.password;
}
}
//Concrete Subject
public class LoginBean extends JPanel implements ActionListener {
private JLabel labUserName, labPassword;
private JTextField txtUserName;
private JPasswordField txtPassword;
private JButton btnLogin, btnClear;
private LoginEventListener lel; //Abstract Observer
private LoginEvent le;
public LoginBean() {
this.setLayout(new GridLayout(3, 2));
labUserName = new JLabel("User Name:");
add(labUserName);
txtUserName = new JTextField(20);
add(txtUserName);
labPassword = new JLabel("Password:");
add(labPassword);
txtPassword = new JPasswordField(20);
add(txtPassword);
btnLogin = new JButton("Login");
add(btnLogin);
btnClear = new JButton("Clear");
add(btnClear);
btnClear.addActionListener(this);
btnLogin.addActionListener(this);//As a concrete observer for another subject,ActionListener as the abstract observer.
}
//Add an observer.
public void addLoginEventListener(LoginEventListener lel) {
this.lel = lel;
}
//private or protected as the notify method
private void fireLoginEvent(Object object, String userName, String password) {
le = new LoginEvent(btnLogin, userName, password);
lel.validateLogin(le);
}
public void actionPerformed(ActionEvent event) {
if (btnLogin == event.getSource()) {
String userName = this.txtUserName.getText();
String password = this.txtPassword.getText();
fireLoginEvent(btnLogin, userName, password);
}
if (btnClear == event.getSource()) {
this.txtUserName.setText("");
this.txtPassword.setText("");
}
}
}
//Abstract Observer
public interface LoginEventListener extends EventListener {
public void validateLogin(LoginEvent event);
}
------------------------------------------------------------------------------------------------------
//Concrete Observer
public class LoginValidatorA extends JFrame implements LoginEventListener {
private JPanel p;
private LoginBean lb;
private JLabel lblLogo;
public LoginValidatorA() {
super("Bank of China");
p = new JPanel();
this.getContentPane().add(p);
lb = new LoginBean();
lb.addLoginEventListener(this);
Font f = new Font("Times New Roman", Font.BOLD, 30);
lblLogo = new JLabel("Bank of China");
lblLogo.setFont(f);
lblLogo.setForeground(Color.red);
p.setLayout(new GridLayout(2, 1));
p.add(lblLogo);
p.add(lb);
p.setBackground(Color.pink);
this.setSize(600, 200);
this.setVisible(true);
}
public void validateLogin(LoginEvent event) {
String userName = event.getUserName();
String password = event.getPassword();
if (0 == userName.trim().length() || 0 == password.trim().length()) {
JOptionPane.showMessageDialog(this, new String("Username or Password is empty!"), "alert", JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, new String("Valid Login Info!"), "alert", JOptionPane.INFORMATION_MESSAGE);
}
}
public static void main(String args[]) {
new LoginValidatorA().setVisible(true);
}
}
------------------------------------------------------------------------------------------------------
public class LoginValidatorB extends JFrame implements LoginEventListener {
private JPanel p;
private LoginBean lb;
private JLabel lblLogo;
public LoginValidatorB() {
super("China Mobile");
p = new JPanel();
this.getContentPane().add(p);
lb = new LoginBean();
lb.addLoginEventListener(this);
Font f = new Font("Times New Roman", Font.BOLD, 30);
lblLogo = new JLabel("China Mobile");
lblLogo.setFont(f);
lblLogo.setForeground(Color.blue);
p.setLayout(new GridLayout(2, 1));
p.add(lblLogo);
p.add(lb);
p.setBackground(new Color(163, 185, 255));
this.setSize(600, 200);
this.setVisible(true);
}
public void validateLogin(LoginEvent event) {
String userName = event.getUserName();
String password = event.getPassword();
if (userName.equals(password)) {
JOptionPane.showMessageDialog(this, new String("Username must be different from password!"), "alert", JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, new String("Rigth details!"), "alert", JOptionPane.INFORMATION_MESSAGE);
}
}
public static void main(String args[]) {
new LoginValidatorB().setVisible(true);
}
}