观察者模式(observer)

本文介绍了观察者模式,它用于解决一对多的依赖关系。定义了对象间一对多依赖,状态改变时依赖对象会自动更新。阐述了需解决的问题、解决方法、优缺点及使用场景,还给出应用实例、UML类图和demo,介绍了JDK自带的观察者模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一句话:解决一对多的依赖关系。

定义:

定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

需要解决的问题:

一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

如何解决:

使用面向对象技术,可以将这种依赖关系弱化。

优点: 

1、观察者和被观察者是抽象耦合的。

2、建立一套触发机制。

缺点:

 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景:

1.一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

2.一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

3.需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

应用实例:

AWT中的事件处理DEM(委派事件模型Delegation Event Model)就是使用观察者模式实现的。junit3也使用观察者实现事件监听。

UML类图:

观察者模式包含如下角色:
Subject: 目标
ConcreteSubject: 具体目标
Observer: 观察者
ObserverImpl: 具体观察者

demo:

1.观察者接口

/**
 * 观察者
 *
 */
public interface Observer {
	public void update(String msg);
}

2.观察者实现类1

package com.pattern.observer;

public class ObserverImpl1 implements Observer {

	@Override
	public void update(String msg) {
		System.out.println("观察者1,收到信息:"+msg);
	}

}

3.观察者实现类2

package com.pattern.observer;

public class ObserverImpl2 implements Observer {

	@Override
	public void update(String msg) {
		System.out.println("观察者2,收到信息:"+msg);
	}

}

4.被观察者抽象类

package com.pattern.observer;

import java.util.ArrayList;
import java.util.List;

/**
 * 被观察者
 *
 */
public abstract class Subject {
    private List<Observer> obs = new ArrayList<Observer>();

    public void addObserver(Observer obs){
        this.obs.add(obs);
    }
    public void delObserver(Observer obs){
        this.obs.remove(obs);
    }
    protected void notifyObserver(String msg){
        for(Observer o: obs){
            o.update(msg);
        }
    }
    public abstract void doSomething();
}

5.被观察者具体类

package com.pattern.observer;

public class ConcreteSubject extends Subject{

	@Override
	public void doSomething() {
        System.out.println("被观察者事件反生");
        this.notifyObserver("hello");
	}

}

6.测试类

package com.pattern.observer;

public class Client {

	public static void main(String[] args) {
		Subject sub = new ConcreteSubject();
		sub.addObserver(new ObserverImpl1()); // 添加观察者1
		sub.addObserver(new ObserverImpl2()); // 添加观察者2
		sub.doSomething();
	}

}

JDK自带的观察者模式

在JDK源码下的java.util.Observable和java.util.Observer,分别代表观察者模式中的Subject和Observer。

Observable

在源码中,有两个notifyObservers方法,其中的主要差别就是一个是自带内容,另一个自带内容为null,其实也就是JDK的Observer接口默认是同时支持推模型和拉模型,如下:

public void notifyObservers() {
        notifyObservers(null);
    }

public void notifyObservers(Object arg) {
        ...
        ...
    }  

在第二个notifyObservers方法中的代码实现,有一同步代码段:

synchronized (this) {
            /* We don't want the Observer doing callbacks into
             * arbitrary code while holding its own Monitor.
             * The code where we extract each Observable from
             * the Vector and store the state of the Observer
             * needs synchronization, but notifying observers
             * does not (should not).  The worst result of any
             * potential race-condition here is that:
             * 1) a newly-added Observer will miss a
             *   notification in progress
             * 2) a recently unregistered Observer will be
             *   wrongly notified when it doesn't care
             */
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

这是为了保证潜在的竞争关系,所以在实现了Observable类中,如果数据源发生了变化,要通知所有的Observer的时候,要先调用setChanged()方法。

 

Observer

Observer类是一个接口,里面就只有一个update的方法:

/**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);

其实这个方法就是同时支持拉模型(把Observable整个对象传递过来了,JDK默认就是传递了整个对象),拉模型(Object对象,对应着Observable里面特有的内容属性)。

demo(气象站):

1.被观察者

package com.pattern.observer;

import java.util.Observable;

/**
 * 被观察者
 *
 */
public class WeatherData  extends Observable {
	private float temperatrue;
	
	private float humidity;
	
	private float pressure;
	
	public WeatherData(){};
	
	public void measurementsChanged(){
		setChanged();
		notifyObservers();
	}
	
	public float getTemperature(){
		return temperatrue;
	}
	
	public float getHumidity(){
		return humidity;
	}
	
	public float getPressure(){
		return pressure;
	}
	
	
	// 天气发生变化
	public void setMeasurements(float temperature, float humidity, float pressure){
		this.temperatrue = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}


}

2.观察者

package com.pattern.observer;

import java.util.Observable;
import java.util.Observer;

/**
 *观察者 
 *
 */
public class CurrentConditionsDisplay implements Observer {
	private Observable observable;
	
	private float temperature;
	
	private float pressure;
	
	private float humidity;
	
	public CurrentConditionsDisplay(Observable observable){
		this.observable = observable;
		this.observable.addObserver(this);
	}
 
	@Override
	public void update(Observable observable, Object obj) {
		if(observable instanceof WeatherData){
			WeatherData weatherData = (WeatherData)observable;
			this.temperature = weatherData.getTemperature();
			this.humidity = weatherData.getHumidity();
			this.pressure = weatherData.getPressure();
			display();
		}
	}
 
	public void display() {
		System.out.println("当前温度:" + this.temperature);
		System.out.println("当期湿度:" + this.humidity);
		System.out.println("当期气压:" + this.pressure);
	}


}

3.测试 

package com.pattern.observer;

public class WeatherStation {
	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
		CurrentConditionsDisplay CurrentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
		weatherData.setMeasurements(23, 35, 12);
	}

}
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haoxin963

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值