最近买了一本设计模式的书,于是就边看边记录一下,然后把它变成实际生产中应用。
所谓观察者模式,简单来说就由观察者和被观察者组成,观察者订阅被观察者,只有订阅了观察者才能收到被观察者的动态信息。
咱们就用生活中简单的例子来说明,如:咱们现在刷的抖音,比如你非常喜欢一个小姐姐的抖音,所以小手一抖点了关注,然后后面这个小姐姐一有动态,你就收到了她的抖音短视频。这里面小姐姐就是那个被观察的对象,而你就是那个观察者,当你点击关注的时候就相当于你订阅了她的抖音动态。
下面咱们上一个非常常见的Android应用场景,咱们在应用市场的时候点击安装一个应用,就会显示进度条,当你点击进去看详情的时候发现进度条也在更新,并且跟外面列表更新一致。这里咱们就可以用到这个观察者模式来实现。
首先咱们先定一个被观察者的接口,如下代码:
package com.app.mode.observer;
public interface Subject<T> {
void registerObserver(Observer<T> observer);
void removeObserver(Observer<T> observer);
void notifyObservers();
}
这个接口就是定义注册,删除和更新的方法,咱们要用它的时候先实现这个接口。如下随意写了一个下载类,这个是伪下载类就是个倒计时显示进度条。如下代码:
package com.app.mode.observer;
import android.os.CountDownTimer;
import java.util.ArrayList;
import java.util.List;
/*
下载任务,观察者
*/
public class DownLoadSubject implements Subject<Integer> {
private List<Observer<Integer>> observers;
private int currentProgress = 0;
private static DownLoadSubject instance;
private CountDownTimer mTimer;
private DownLoadSubject() {
observers = new ArrayList<>();
mTimer = new CountDownTimer(100 * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
currentProgress += 1;
notifyObservers();//进度改变通知更新
}
@Override
public void onFinish() {
}
};
mTimer.start();
}
public static DownLoadSubject getInstance() {
if (instance == null)
instance = new DownLoadSubject();
return instance;
}
@Override
public void registerObserver(Observer<Integer> observer) {
if (observers.indexOf(observer) == -1) {//注册观察者,判断当前观察者对象中有没有被添加,没有添加就添加到队列中
observers.add(observer);
}
}
@Override
public void removeObserver(Observer<Integer> observer) {
if (observers.indexOf(observer) != -1) {//注册观察者,判断当前观察者对象中有没有被添加
observers.remove(observer);
}
}
@Override
public void notifyObservers() {//遍历队列,通知观察者更新
for (Observer<Integer> observer : observers) {
observer.onUpdate(currentProgress);
}
}
}
这个类其实还用到了一个单例模式,并且这个单例模式是有问题的,特别是在多线程下操作的时候,这个后面会详细介绍,这里只要记得一定要单例模式确保咱们进度条一致性。
接下来就是观察者了,咱们先定义一个接口,如下:
package com.app.mode.observer;
public interface Observer<T> {
void onUpdate(T t);
}
这里其实就是一个更新的方法,接下来就是是实现该方法了。如下:
package com.app.mode.observer.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.SeekBar;
import com.app.mode.R;
import com.app.mode.observer.DownLoadSubject;
import com.app.mode.observer.Observer;
//这里相当于应用商城的列表页,点击下载的时候出现进度条,点击详情页就显示应用详情进度条也会更新到当前进度
public class ObserverActivity extends AppCompatActivity implements Observer<Integer> {//这里也是观察者
private SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_observer);
DownLoadSubject.getInstance().registerObserver(this);
seekBar = findViewById(R.id.seekBar);
}
@Override
public void onUpdate(Integer integer) {
seekBar.setProgress(integer);
}
@Override
protected void onDestroy() {
super.onDestroy();
DownLoadSubject.getInstance().removeObserver(this);//这里记得删除当前观察者,不然会报异常
}
public void startDetail(View view) {
startActivity(new Intent(getApplicationContext(), ObserverActivityDetail.class));
}
}
这是外面一个列表的显示,就是一个activity然后实现观察者接口。然后这个activity就变成了观察者了,下面详情页实现这个观察者接口,如下:
package com.app.mode.observer.activity;
import android.os.Bundle;
import android.widget.SeekBar;
import androidx.appcompat.app.AppCompatActivity;
import com.app.mode.R;
import com.app.mode.observer.DownLoadSubject;
import com.app.mode.observer.Observer;
public class ObserverActivityDetail extends AppCompatActivity implements Observer<Integer> {
private SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acitivity_observer_detail);
DownLoadSubject.getInstance().registerObserver(this);
seekBar = findViewById(R.id.seekBar);
}
@Override
public void onUpdate(Integer integer) {
seekBar.setProgress(integer);
}
@Override
protected void onDestroy() {
super.onDestroy();
DownLoadSubject.getInstance().removeObserver(this);
}
}
ok,观察者这样就实现了。
其实这个观察者模式在java代码中早已实现,如下:
这里只是比我那里多了一个参数,然后被观察者是Observable这里就不贴出来了,这类中实现方法差不多,但是它这里功能比较全然后观察者用的是Vector集合。
Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:
- Vector 是同步访问的。
- Vector 包含了许多传统的方法,这些方法不属于集合框架。
这个大家可以自己去看源码,加深理解。
至于实现效果,想看的直接代码跑起来就可以看到了,这里就不做gif动图显示了。
后续把所有学习到的模式全部介绍一下,跟大家一起学习加深理解
代码地址:GitHub