Øriginally posted on my blog at henricodesjava.blog
Hi everyone! Chapter two in Head First Design Patterns: A Brain-Friendly Guide is all about the Observer Pattern. They make note of how fundamental and frequently this pattern is used. And also allude to the idea that future patterns in this book are based on this and other pattern combinations. So lets talk about the Observer Pattern.
这种模式试图解决的问题是关于沟通和管理。 文中给出的一个简单的抽象示例是关于一家报纸出版公司及其订阅者的。 从技术上讲,此关系可以归类为一对多关系,一个发布者和许多订阅者。 文本使用术语“€”学科–指发布者,术语–观察者指代订户。
接下来,我将给出一个更具体的示例。 我将使用一个与文本稍有不同的示例来说明这个想法。 可以说我们是一家金融初创公司,并且我们有一个智能手表应用程序的构想,该应用程序可以与您所有的金融机构进行通信,从而使您对财务状况有一个大致的了解。 例如,它可以显示您的支票帐户余额,或显示您拥有的股票价格。 我们可以访问的是一个可以为我们返回这些值的类,让我们将此类称为财务数据。 就本示例而言,我们不在乎它如何检索此信息。
以下是我们智能手表应用程序的简单实施,并附有说明。 当然,所有这些只是伪代码,没有实际的smartwatch代码。
此实现存在一些问题。 首先,我们从第一章开始就违反了设计原则。 _确定应用程序中各个方面的不同,并将它们与保持不变的部分分开。 _带有绿色箭头的线表示手表上的其他屏幕,将来我们可能希望添加更多屏幕。 不幸的是,到那时,对此类的更改是不可避免的。 带有红色箭头的线表示正在检索财务数据,虽然这也可以更改,但这将是API更改引起的更改,而不是客户端代码的更改。 我们还违反了另一个设计原则:将程序编程为接口,而不是实现。 _如果只有一种方法,我们可以将变更后的代码与没有变更的代码整齐地分开,也可以将没有编程的代码分离到实现中? 介绍者,观察者模式!
观察者模式:定义对象之间的一对多依赖关系,以便当一个对象更改状态时,将自动通知并更新所有依赖关系。
我们将完成此操作,并通过使用接口引入松散耦合。 让我们用一个类图来说明这个定义。
现在,以这些类图为指南,让我们来看看我们的智能手表应用程序的实现。 首先,下面是两个接口。
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
public interface Observer {
public void upate(Object obj);
}
接下来,让我们看看实现了Subject接口的新FinancialData类。
public class FinancialData implements Subject {
private ArrayList observers;
private float checkingBalance;
private float savingsBalance;
private float stockValue;
private float fourOnekValue;
private float weekSpending;
private float monthSpending;
public FinancialData(){
observers = new ArrayList();
}
public void registerObserver(Observer o){
observers.add(o);
}
public void removeObserver(o){
int i = observers.indexOf(o);
if(i > 0){
observers.remove(i);
}
}
public void notifyObservers(){
for(int i = 0; i<observers.size(); i++){
Observer observer = (Observer)observers.get(i);
observer.update(this);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setNewBalanceData(float val1, float val2){
this.checkingBalance = val1;
this.savingsBalance = val2;
measurementsChanged();
}
public void setNewInvestmentData(float val1, float val2){
this.stockValue = val1;
this.fourOnekValue = val2;
measurementsChanged();
}
public void setNewSpendingData(float val1, float val2){
this.weekSpending = val1;
this.monthSpending = val2;
measurementsChanged();
}
// other FinancialData methods here
// including getter methods for balance, investment, and spending values
}
现在,让我们看一下我们的观察者之一,Balance智能手表屏幕。
public class BalanceScreen implements Observer {
private float checkingBal;
private float savingsBal;
private Subject financialData;
public BalanceScreen(Subject financialData){
this.financialData = financialData;
financialData.registerObserver(this);
}
public void update(Object obj){
if( obj instanceof FinancialData){
FinancialData fd = (FinancialData) obj;
this.checkingBal = fd.getCheckingBalance();
this.savingsBal = fd.getSavingsBalance();
}
display();
}
// other BalanceScreen methods here
}
最后,让我们看一个将所有这些粘合在一起的程序。
public class SmartWatch {
public static void main(String[] args){
FinancialData financialData = new FinancialData();
BalanceScreen balanceScreen = new BalanceScreen(financialData);
InvestmentScreen investmentScreen = new InvestmentScreen(financialData);
SpendingScreen spendingScreen = new SpendingScreen(financialData);
// not using an actualy finance api, so we set values manually
financialData.setNewBalanceData(348.12, 3600.87);
financialData.setNewInvestmentData(899.12, 45000.65);
financialData.setNewSpendingData(210.34, 677.45);
// at this point we should see print statements for all 3 screens
}
}
你有它! 我们实现了接口并创建了一些代码对其进行测试。 现在请注意,我实际上并未运行此代码,因此这些行中可能存在一两个错误。 对于以后的文章,我将不得不创建一个项目并将此工作代码推到github上。 感谢您的阅读!ðŸ'‹ðŸ½
(originally posted at my personal blog: https://henricodesjava.blog)