一对一免费咨询: 18215660330

假设我们正在构建一个cricket应用程序,通知观众有关当前得分,运行率等信息。假设我们已经制作了两个显示元素CurrentScoreDisplay和AverageScoreDisplay。CricketData具有所有数据(运行,碗等),每当数据发生变化时,显示元素都会通过新数据通知,并相应地显示最新数据。O1

下面是这个设计的java实现。

filter_none
编辑
play_arrow

brightness_4
// Java implementation of above design for Cricket App. The
// problems with this design are discussed below.

// A class that gets information from stadium and notifies
// display elements, CurrentScoreDisplay & AverageScoreDisplay
class CricketData
{
int runs, wickets;
float overs;
CurrentScoreDisplay currentScoreDisplay;
AverageScoreDisplay averageScoreDisplay;

// Constructor
public CricketData(CurrentScoreDisplay currentScoreDisplay,
AverageScoreDisplay averageScoreDisplay)
{
this.currentScoreDisplay = currentScoreDisplay;
this.averageScoreDisplay = averageScoreDisplay;
}

// Get latest runs from stadium
private int getLatestRuns()
{
// return 90 for simplicity
return 90;
}

// Get latest wickets from stadium
private int getLatestWickets()
{
// return 2 for simplicity
return 2;
}

// Get latest overs from stadium
private float getLatestOvers()
{
// return 10.2 for simplicity
return (float)10.2;
}

// This method is used update displays when data changes
public void dataChanged()
{
// get latest data
runs = getLatestRuns();
wickets = getLatestWickets();
overs = getLatestOvers();

currentScoreDisplay.update(runs,wickets,overs);
averageScoreDisplay.update(runs,wickets,overs);
}
}

// A class to display average score. Data of this class is
// updated by CricketData
class AverageScoreDisplay
{
private float runRate;
private int predictedScore;

public void update(int runs, int wickets, float overs)
{
this.runRate = (float)runs/overs;
this.predictedScore = (int) (this.runRate * 50);
display();
}

public void display()
{
System.out.println(“\nAverage Score Display:\n” +
“Run Rate: ” + runRate +
“\nPredictedScore: ” + predictedScore);
}
}

// A class to display score. Data of this class is
// updated by CricketData
class CurrentScoreDisplay
{
private int runs, wickets;
private float overs;

public void update(int runs,int wickets,float overs)
{
this.runs = runs;
this.wickets = wickets;
this.overs = overs;
display();
}

public void display()
{
System.out.println(“\nCurrent Score Display: \n” +
“Runs: ” + runs +”\nWickets:”
+ wickets + “\nOvers: ” + overs );
}
}

// Driver class
class Main
{
public static void main(String args[])
{
// Create objects for testing
AverageScoreDisplay averageScoreDisplay =
new AverageScoreDisplay();
CurrentScoreDisplay currentScoreDisplay =
new CurrentScoreDisplay();

// Pass the displays to Cricket data
CricketData cricketData = new CricketData(currentScoreDisplay,
averageScoreDisplay);

// In real app you would have some logic to call this
// function when data changes
cricketData.dataChanged();
}
}
输出:

当前分数显示:
运行:90
售票窗口:2
Overs:10.2

平均分数显示:
运行率:8.823529
PredictedScore:441
上述设计存在的问题:

CricketData保存对具体显示元素对象的引用,即使它只需要调用这些对象的更新方法。它可以访问太多额外的信息。
这句话“currentScoreDisplay.update(run,wickets,overs);”违反了最重要的设计原则之一“程序到接口,而不是实现。”因为我们使用具体对象来共享数据而不是抽象接口。
CricketData和显示元素紧密耦合。
如果将来有另一个需求,我们需要添加另一个显示元素,我们需要更改代码的非变化部分(CricketData)。这绝对不是一个好的设计实践,应用程序可能无法处理更改而且不易维护。
如何避免这些问题?
使用观察者模式

观察者模式

要理解观察者模式,首先需要了解主题和观察者对象。

主题和观察者之间的关系可以很容易地理解为杂志订阅的类比。

杂志出版商(主题)在业务中并出版杂志(数据)。
如果您(数据/观察员的用户)对您订阅的杂志(注册)感兴趣,并且如果发布了新版本,则会将其发送给您。
如果您取消订阅(取消注册),则会停止获取新版本。
出版商不知道你是谁以及你如何使用该杂志,它只是将它交付给你,因为你是订阅者(松耦合)。
定义:

Observer模式定义了对象之间的一对多依赖关系,以便一个对象更改状态,其所有依赖关系都会自动得到通知和更新。

说明:

主体(一)和观察者(许多)之间存在一对多的依赖关系。
由于观察者本身无法访问数据,因此存在依赖性。他们依赖于Subject来提供数据。
类图:O2

这里Observer和Subject是接口(可以是任何抽象超类型,不一定是java接口)。
所有需要数据的观察者都需要实现观察者界面。
observer接口中的notify()方法定义主题为其提供数据时要采取的操作。
主题维护一个observerCollection,它只是当前注册(订阅)观察者的列表。
registerObserver(observer)和unregisterObserver(observer)分别是添加和删除观察者的方法。
更改数据时需要调用notifyObservers(),并且需要为观察者提供新数据。
优点:
在交互的对象之间提供松散耦合的设计。松散耦合的对象可灵活适应不断变化的要求。松散耦合意味着交互对象应该具有较少的彼此信息。

观察者模式提供这种松耦合:

Subject只知道观察者实现Observer接口。没有更多。
无需修改Subject来添加或删除观察者。
我们可以相互独立地重用主题和观察者类。
缺点:

由于显式注册和取消注册观察者而导致由Lapsed侦听器问题导致的内存泄漏。
什么时候使用这种模式?
当多个对象依赖于一个对象的状态时,您应该考虑在应用程序中使用此模式,因为它为相同的对象提供了一个整洁且经过良好测试的设计。

真实生活用途:

它在GUI工具包和事件监听器中大量使用。在java中,按钮(subject)和onClickListener(observer)使用观察者模式建模。
社交媒体,RSS订阅,电子邮件订阅,您可以选择关注或订阅,并收到最新通知。
如果有更新,Play商店中应用的所有用户都会收到通知。

需要软件开发就找我们吧。

成都软件开发 最好的成都软件定制开发公司
18215660330