观察者模式|集合1(简介)

让我们首先考虑下面的场景来理解观察者模式。

null

脚本 :

假设我们正在构建一个板球应用程序,它会通知观众有关当前分数、跑步率等信息。假设我们制作了两个显示元素CurrentScoreDisplay和AverageScoreDisplay。CricketData拥有所有数据(跑步、保龄球等),每当数据更改时,显示元素都会收到新数据的通知,并相应地显示最新数据。 o1

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

// 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( "Average Score Display:" +
"Run Rate: " + runRate +
"PredictedScore: " + 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( "Current Score Display: " +
"Runs: " + runs + "Wickets:"
+ wickets + "Overs: " + 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();
}
}


输出:

Current Score Display: 
Runs: 90
Wickets:2
Overs: 10.2

Average Score Display:
Run Rate: 8.823529
PredictedScore: 441

以上设计的问题 :

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

如何避免这些问题? 使用观察者模式

观察者模式

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

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

  • 杂志出版商(主题)从事出版杂志(数据)的业务。
  • 如果你(数据用户/观察者)对你订阅(注册)的杂志感兴趣,并且如果新版本出版,它会被交付给你。
  • 如果你取消订阅(取消注册),你将停止获得新版本。
  • Publisher不知道你是谁,也不知道你是如何使用杂志的,它只是把杂志发给你,因为你是订阅者(松散耦合)。

定义:

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

说明:

  • 一对多依赖是主体(一)和观察者(多)之间的依赖。
  • 由于观察者本身无法访问数据,因此存在依赖性。他们依靠受试者向他们提供数据。

类图: o2

图片来源: 维基百科

  • 这里Observer和Subject是接口(可以是任何抽象超类型,不一定是java接口)。
  • 所有需要数据的观察者都需要实现观察者接口。
  • observer接口中的notify()方法定义了主体提供数据时要采取的操作。
  • 主体维护一个observerCollection,它只是当前注册(订阅)的观察者列表。
  • registerObserver(观察者)和unregisterObserver(观察者)分别是添加和删除观察者的方法。
  • 当数据发生更改并且需要向观察者提供新数据时,将调用notifyObservators()。

优势: 在交互对象之间提供松散耦合的设计。松散耦合的对象可以灵活地适应不断变化的需求。在这里,松耦合意味着相互作用的对象应该彼此拥有较少的信息。

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

  • 主体只知道观察者实现了观察者接口。没别的了。
  • 不需要修改主题来添加或删除观察者。
  • 我们可以独立地重用subject和observer类。

缺点:

什么时候使用这种模式? 当多个对象依赖于一个对象的状态时,应考虑在该应用程序中使用此模式,因为它提供了一个整洁且经过良好测试的设计。

现实生活中的用途:

  • 它在GUI工具包和事件侦听器中大量使用。在java中,按钮(subject)和onClickListener(observer)是用observer模式建模的。
  • 社交媒体、RSS源、电子邮件订阅,您可以选择关注或订阅,并收到最新通知。
  • play store上应用程序的所有用户都会收到更新通知。

观察者模式|集2(实现)

进一步阅读—— Python中的观察者方法

本文由 苏拉布·库马尔 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以写一篇文章,然后将文章邮寄给评论-team@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写评论

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享