前情提要
上一個小作文中,我們通過接口的形式實現了JAVA的回調函數,做到了一對一的消息通知或者說方法調用,"下載器只需要通知迅雷對象,實際可能會通知多種對象",按照上一節(jié)的思路實現一個下載器通知多個對象,下載器需要聚合多個對象,并且還要考慮聚合對象的初始化問題,按照這個思路是不容易實現,一對多的方法調用的。
想要實現一方調用多方的方法該具備怎樣的條件?
1.一方應該持有多方的引用
2.多方應該有相同的方法調用入口
普通實現
public class One{
DualA a;
DualB b;
//***省略多方
public initA(DualA a){
this.a = a;
}
public initB(DualB b){
this.b = b;
}
public void toInvokeMethod(){
a.methodA();
b.methodB();
//....
}
public static void main(String[] args){
One one = new One();
one.initA(new A());
//....
one.toInvokeMethod();
}
}
public class DualA {
void methodA(){}
}
public class DualB {
void methodB(){}
}
從上述的代碼中可以清晰的看出這些問題:
Q1.如果有更多的多方需要被調用,需要組合更多類
Q2.需要調用太多不同的init方法為引用賦值(不然會空指針)
怎樣可以做到調用一個方法解決引用賦值的問題(組合類太多、賦值方法太多)?
所有類都有一個父類Object,可以組合一個Object的集合解決組合類太多問題,賦值方法太多也順便解決。
public class One{
List<Object> list
void initList(Object o){ //void initA(A a) {this.a = a}
list.add(o);
}
void toInvokeMethod(){
}
}
這個時候toInvokeMthod如何實現?
遍歷集合!取出Object對象,會發(fā)現沒有我們需要調用的方法,使用多態(tài)的思想,多方實現一個公共的接口,各自重寫里邊的調用方法,這樣遍歷后就可以滿足要求。
public interface ObserverInterface {
void update(Object o);
}
public class Observer1 implements ObserverInterface{
@Override
public void update(Object o) {
System.out.println("o1 do something");
}
}
public class Observer2 implements ObserverInterface{
@Override
public void update(Object o) {
System.out.println("o2 do something");
}
}
public class Subject{
List<ObserverInterface> list;
public void addObserver(ObserverInterface o){
list.add(o);
}
public void notify(){
list.foreach(item -> item.update(new Object())) ;//可以傳基本數據類型,引用數據類型
}
public static void main(String[] args){
ObserverInterface o1 = new Observer1();
ObserverInterface o2 = new Observer2();
Subject sub = new Subject();
sub.addObserver(o1);
sub.addObserver(o2);
sub.notify();
}
}
可以看出問題,在subject的notify方法調用的update沒起到傳遞有效數據的效果,這些數據只能寫死,該如何解決死數據的問題吶?
list.foreach(item -> item.update(new Object()));
list.foreach(item -> item.update(1)) ;
list.foreach(item -> item.update("ABC")) ;
1.讓subject這個對象有屬性,通過方法為屬性賦值,將subject當作參數傳遞,這樣在update時數據就不是死的
public class Subject implements SubjectInterface{
String name;
public Subject(String name){
this.name = name;
}
//....省略相同代碼
public boolean notifyObserver() {
if(observers == null){
return false;
}
observers.forEach(item -> item.update(this));
return true;
}
}
public class Observer1 implements ObserverInterface{
public void update(Object o) {
String name = (String) o;
System.out.println("o1 do something" + " name:"+name);
}
}
public static void main(String[] args){
ObserverInterface o1 = new Observer1();
ObserverInterface o2 = new Observer2();
Subject sub = new Subject("zhangsan");
sub.addObserver(o1);
sub.addObserver(o2);
sub.notify();
}
2.構造一個數據對象
public class Data{
String name;
}
void update(Data data){}
void notify(Data data){
observers.forEach(item -> item.update(data));
}
Data d = new Data("zhangsan");
subject.notify(d);//完成調用
類圖

思考:用戶在系統中剛注冊,需要為用戶初始化積分和個人設置,該如何實現。
觀察者模式實現
1.獲取被觀察者(主題)
2.獲得觀察者
3.將觀察者和被觀察者綁定
4.被觀察者(主題)調用通知方法
5.觀察者調用方法
public class Main {
public static void main(String[] args) {
RegisteSub concurrentSubject = new RegisteSub();
ObserverInterface pointsObserver = new PointsObserver();
UserObserver userObserver = new UserObserver();
concurrentSubject.addListener(pointsObserver);
concurrentSubject.addListener(userObserver);
RegisterService registerService = new RegisterService();
boolean success = registerService.registerByTel();
if(success){
concurrentSubject.notifyObserver();
}
}
主題和主題接口
public interface SubjectInterface {
boolean addListener(ObserverInterface observer);
boolean removeListener(ObserverInterface observer);
void notifyObserver();
}
public class RegisteSub implements SubjectInterface{
List<ObserverInterface> observers;
@Override
public boolean addListener(ObserverInterface observer) {
if(observers == null){
observers = new ArrayList<>();
}
return observers.add(observer);
}
@Override
public boolean removeListener(ObserverInterface observer) {
if(observers!=null){
return observers.remove(observer);
}
return false;
}
@Override
public void notifyObserver() {
observers.forEach(item -> item.update(this));
}
void registerUserByTel(String tel){
System.out.println(tel + "注冊成功");
notifyObserver();
}
}
觀察者和觀察者接口
public interface ObserverInterface {
void update(Object o);
}
public class PointsObserver implements ObserverInterface{
@Override
public void update(Object o) {
System.out.println("積分系統:初始化!");
}
}
一般實現
public class registeController{
@Override
RegisterService registerService;
@Override
PointsService pointsService;
@Override
UserService userService;
public void regitser(String tel){
boolean success = registerService.registeByTel(tel);//
if(success){ //注冊成功,則調用積分服務和個人設置服務的初始化方法
pointsService.init(tel);
userService.init(tel);
}
}
static class RegisterService{
public boolean registerByTel(){
return true;
}
}
}
開發(fā)中這樣實現功能的代碼應該是最為普遍的,假設現在有新需求:當注冊成功后,需要初始化用戶的好友列表,在上述代碼基礎上,我們不得不修改類,為其注入新的服務,并修改方法的調用,這樣違背了開閉原則。在不使用MQ和違背開閉原則的基礎上,我們該如何實現這個需求吶?敬請期待!使用觀察者模式的訂閱發(fā)布模型實現的事務驅動(spring 簡版)!
引用博客
https://zhuanlan.zhihu.com/p/431748712 #類圖是偷的這個哥們的