Java设计模式详谈(三):观察者

        观察者模式又叫作(发布-订阅)模式,属于行为型模式的一种,它定义了一种一对多的关系,当多个观察者同时监听到被观察者出现的变化,就会作出对应的处理。

        废话不多说,今天分享一下关于观察者模式相关的内容。废话不多说,接下来直接进入代码实例。

观察者接口:

/**
 * 观察者接口
 * @author lyr
 * @date 2017年11月27日
 */
public interface Observer {
	
	void update(Observable o);
}

 

被观察者:

public class ConcreateObserver1 implements Observer{

	public void update(Observable o) {
		System.out.println("观察者1发现"+o.getClass().getSimpleName()+"出现变化!");
		System.out.println("观察者1作出回应...");
	}

}
public class ConcreateObserver2 implements Observer{

	public void update(Observable o) {
		System.out.println("观察者2发现 "+o.getClass().getSimpleName()+"出现变化!");
		System.out.println("观察者2作出回应...");
	}

}


具体的操作:

public class Observable {

	List<Observer> observers = new ArrayList<Observer>();
	
	public void addObserver(Observer o){
		observers.add(o);
	}
	
	public void change(){
		System.out.println("我是被观察者,我已经发生变化了!");
		notifyObservers();
	}
	
	public void notifyObservers(){
		for(Observer obs:observers){
			obs.update(this);
		}
	}
}

 


测试

public class Client {

	public static void main(String[] args) {
		Observable obsable = new Observable();
		obsable.addObserver(new ConcreateObserver1());
		obsable.addObserver(new ConcreateObserver2());
		obsable.change();
	}
}


下面是测试结果

       虽然上面的代码很low,不过足够说明问题。从上面的几步下来可以很清楚的看到,被观察者出现变化的时候,它会通知其它的观察者,当观察者捕获到被观察者发出的通知,就会根据各自的需要作出相应的处理。不过这里需要注意的是,这些类都是自定义的类,并不是JDK中的相关类,所以要注意区分。

       还有一点的就是,观察者模式分离了观察者和被观察者的责任,让它们自己去维护各自的功能模块区域,从而提高系统的可重用性和可维护性。

Java内置的观察者模式

在java.util包里面,包含了基本的Observer接口和Observable抽象类,在使用方面除了上述实现的功能还有注册、删除等等,并且通知观察者的那些功能都已经内置了。

先来看下观察者接口:

//观察者接口,每一个观察者都必须实现这个接口
public interface Observer {
    //这个方法是观察者在观察对象产生变化时所做的响应动作,从中传入了观察的对象和一个预留参数
    void update(Observable o, Object arg);
}

而下面则是被观察类:

import java.util.Vector;

//被观察者类
public class Observable {
    //这是一个改变标识,来标记该被观察者有没有改变
    private boolean changed = false;
    //持有一个观察者列表
    private Vector obs;
    
    public Observable() {
    obs = new Vector();
    }
    //添加观察者,添加时会去重
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
          }
    }
    //删除观察者
    public synchronized void deleteObserver(Observer o) {
           obs.removeElement(o);
    }
    //notifyObservers(Object arg)的重载方法
    public void notifyObservers() {
           notifyObservers(null);
    }
    //通知所有观察者,被观察者改变了,你可以执行你的update方法了。
    public void notifyObservers(Object arg) {
        //一个临时的数组,用于并发访问被观察者时,留住观察者列表的当前状态,这种处理方式其实也算是一种设计模式,即备忘录模式。
        Object[] arrLocal;
    //注意这个同步块,它表示在获取观察者列表时,该对象是被锁定的
    //也就是说,在我获取到观察者列表之前,不允许其他线程改变观察者列表
    synchronized (this) {
        //如果没变化直接返回
        if (!changed)
                return;
            //这里将当前的观察者列表放入临时数组
            arrLocal = obs.toArray();
            //将改变标识重新置回未改变
            clearChanged();
        }
        //注意这个for循环没有在同步块,此时已经释放了被观察者的锁,其他线程可以改变观察者列表
        //但是这并不影响我们当前进行的操作,因为我们已经将观察者列表复制到临时数组
        //在通知时我们只通知数组中的观察者,当前删除和添加观察者,都不会影响我们通知的对象
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    //删除所有观察者
    public synchronized void deleteObservers() {
          obs.removeAllElements();
    }

    //标识被观察者被改变过了
    protected synchronized void setChanged() {
          changed = true;
    }
    //标识被观察者没改变
    protected synchronized void clearChanged() {
          changed = false;
    }
    //返回被观察者是否改变
    public synchronized boolean hasChanged() {
         return changed;
    }
    //返回观察者数量
    public synchronized int countObservers() {
         return obs.size();
    }
}

在使用Java内置的观察者模式的时候还需要注意一个问题,就是notifyObservers这个方法中的一段代码:

for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);

你会发现当在update的过程中出现异常的时候,自此之后的其它观察者就接收不到通知信息了,这个问题我是在观看一位前辈介绍关于观察者模式的时候他提到的,我估计sun公司应该会考虑到这个问题,但是现在看来并没有对他进行处理。所以按照正常的情况下,我在发现这个问题的时候一般的都会用try...catch语句块包裹这个方法,也就是如下代码所示:

for (int i = arrLocal.length-1; i>=0; i--){
        try {
		((Observer)arrLocal[i]).update(this, arg);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

这样对它进行处理之后,如果存在问题,也不会影响后面的观察者进行更新的状态。

当然了,你说除此之外观察者模式没有其它的问题是不可能的,一般来说应该是设计上的问题,毕竟被观察者和观察者是一对多的关系,如果反过来就没法用了。而且,每一个观察者都要实现观察者接口,才能添加到被观察者的列表中。如果说一个观察者已经存在,而且没办法更改其代码,那么就没办法成为一个真正的观察者,不过这个问题可以通过适配器模式处理掉。

这次的分享就到这里吧,下一篇再见!

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值