美文网首页
安卓设计模式之观察者模式

安卓设计模式之观察者模式

作者: BlueSocks | 来源:发表于2022-10-12 19:08 被阅读0次

什么是观察者模式?

观察者模式是一种设计模式,它在对象之间建立一对多依赖关系。每当其中一个对象(“主体”或“可观察”)的状态发生变化时,所有其他依赖于它的对象(“观察者”)都会收到通知。

此模式与发布-订阅模式非常相似。主体或可观察对象向相关观察者发布通知,甚至不知道有多少观察者订阅了它,或者他们是谁 ——可观察者只知道他们应该实现一个接口,而不必担心观察者可能会执行什么操作。

观察者模式的优势

  • 受试者对其观察者知之甚少。它唯一知道的是,观察者实现或同意某个契约或接口。
  • 受试者可以在不涉及观察者的情况下重复使用,观察者也是如此。
  • 不对主题进行任何修改以容纳新的观察者。新的观察者只需要实现一个主体知道的接口,然后注册到主体。
  • 观察者可以注册到其注册的多个主题。

所有这些优点都为您提供了代码中模块之间的松散耦合,从而使您能够为应用程序构建灵活的设计。在本文的其余部分,我们将介绍如何创建自己的观察者模式实现,我们还将使用内置的Java Observer/可观察API,并研究可以提供此类功能的第三方库。

建立我们自己的观察者模式

1. 创建主题界面

我们首先定义一个主体(可观察量)将实现的接口。


`public` `interface` `Subject {`

`void` `registerObserver(RepositoryObserver repositoryObserver);`

`void` `removeObserver(RepositoryObserver repositoryObserver);`

`void` `notifyObservers();`

`}`

在上面的代码中,我们创建了一个包含三种方法的接口。第一种方法,正如它所说,将向主体注册一个类型的观察者(我们很快就会创建该接口)。 将被要求删除想要停止从主题接收通知的观察者,最后,每当有变化时,将向所有观察者发送广播。现在,让我们创建一个具体的主题类,它将实现我们创建的主题接口:


`import` `android.os.Handler;`

`import` `java.util.ArrayList;`

`public` `class` `UserDataRepository` `implements` `Subject {`

`private` `String mFullName;`

`private` `int` `mAge;`

`private` `static` `UserDataRepository INSTANCE =` `null``;`

`private` `ArrayList<RepositoryObserver> mObservers;`

`private` `UserDataRepository() {`

`mObservers =` `new` `ArrayList<>();`

`getNewDataFromRemote();`

`}`

`// Simulate network`

`private` `void` `getNewDataFromRemote() {`

`final` `Handler handler =` `new` `Handler();`

`handler.postDelayed(``new` `Runnable() {`

`@Override`

`public` `void` `run() {`

`setUserData(``"Chike Mgbemena"``,` `101``);`

`}`

`},` `10000``);`

`}`

`// Creates a Singleton of the class`

`public` `static` `UserDataRepository getInstance() {`

`if``(INSTANCE ==` `null``) {`

`INSTANCE =` `new` `UserDataRepository();`

`}`

`return` `INSTANCE;`

`}`

`@Override`

`public` `void` `registerObserver(RepositoryObserver repositoryObserver) {`

`if``(!mObservers.contains(repositoryObserver)) {`

`mObservers.add(repositoryObserver);`

`}`

`}`

`@Override`

`public` `void` `removeObserver(RepositoryObserver repositoryObserver) {`

`if``(mObservers.contains(repositoryObserver)) {`

`mObservers.remove(repositoryObserver);`

`}`

`}`

`@Override`

`public` `void` `notifyObservers() {`

`for` `(RepositoryObserver observer: mObservers) {`

`observer.onUserDataChanged(mFullName, mAge);`

`}`

`}`

`public` `void` `setUserData(String fullName,` `int` `age) {`

`mFullName = fullName;`

`mAge = age;`

`notifyObservers();`

`}`

`}`

上面的类实现 Subject 接口。我们有一个数组列表,它保存观察器,然后在私有构造函数中创建它。观察者通过添加到数组列表进行注册,同样,通过从数组列表中删除来取消注册。

请注意,我们正在模拟网络请求以检索新数据。 一旦调用 setUserData()方法并给定全名和年龄的新值,我们就调用 notifyObservers()方法,正如它所说,该方法通知或发送有关新数据更改的广播给所有注册观察者。还会传递全名和年龄的新值。这个主题可以有多个观察者,但在本教程中,我们将只创建一个观察者。但首先,让我们创建观察者接口。

2. 创建观察者界面

public interface RepositoryObserver {
    void onUserDataChanged(String fullname, int age);
}

在上面的代码中,我们创建了具体观察者应该实现的观察者接口。这使我们的代码更加灵活,因为我们编码的是接口而不是具体的实现。一个具体的类不需要知道它可能有许多具体的观察者;它所知道的关于它们的只是它们实现了接口。SubjectRepositoryObserver

现在,让我们创建一个实现此接口的具体类。

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
 
public class UserProfileActivity extends AppCompatActivity implements RepositoryObserver {
    private Subject mUserDataRepository;
    private TextView mTextViewUserFullName;
    private TextView mTextViewUserAge;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_profile);
 
        mTextViewUserAge = (TextView) findViewById(R.id.tv_age);
        mTextViewUserFullName = (TextView) findViewById(R.id.tv_fullname);
 
        mUserDataRepository = UserDataRepository.getInstance();
        mUserDataRepository.registerObserver(this);
    }
 
    @Override
    public void onUserDataChanged(String fullname, int age) {
        mTextViewUserFullName.setText(fullname);
        mTextViewUserAge.setText(age);
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mUserDataRepository.removeObserver(this);
    }
}

在上面的代码中要注意的第一件事是实现接口 - 因此它必须实现方法。在 Activity 的方法中,我们得到了一个实例,然后对其进行初始化并最终将此观察者注册到该实例。
在该方法中,我们希望停止接收通知,因此我们取消注册接收通知。

在该方法中,我们希望使用新的数据值集更新小部件。

现在我们只有一个观察者类,但是我们可以轻松地创建其他想要成为该类的观察者的类。例如,我们可以很容易地有一个,它希望通过成为观察者来通知用户数据的变化。

推拉模型

在上面的示例中,我们使用观察者模式的推送模型。在此模型中,受试者通过传递更改的数据来通知观察者有关更改的信息。但在拉模型中,受试者仍然会通知观察者,但它实际上并没有传递更改的数据。然后,观察者在收到通知后提取所需的数据。

利用 Java 的内置观察者 API

到目前为止,我们已经创建了自己的观察者模式实现,但Java在其API中内置了观察者/可观察者支持。在本节中,我们将使用它。正如您将看到的,此 API 简化了一些实现。

1. 创建可观察量

我们的主题或可观察的主体现在将扩展超类以成为Observable。这是一个希望被一个或多个观察者观察的类。


`import` `android.os.Handler;`

`import` `java.util.Observable;`

`public` `class` `UserDataRepository` `extends` `Observable {`

`private` `String mFullName;`

`private` `int` `mAge;`

`private` `static` `UserDataRepository INSTANCE =` `null``;`

`private` `UserDataRepository() {`

`getNewDataFromRemote();`

`}`

`// Returns a single instance of this class, creating it if necessary.`

`public` `static` `UserDataRepository getInstance() {`

`if``(INSTANCE ==` `null``) {`

`INSTANCE =` `new` `UserDataRepository();`

`}`

`return` `INSTANCE;`

`}`

`// Simulate network`

`private` `void` `getNewDataFromRemote() {`

`final` `Handler handler =` `new` `Handler();`

`handler.postDelayed(``new` `Runnable() {`

`@Override`

`public` `void` `run() {`

`setUserData(``"Mgbemena Chike"``,` `102``);`

`}`

`},` `10000``);`

`}`

`public` `void` `setUserData(String fullName,` `int` `age) {`

`mFullName = fullName;`

`mAge = age;`

`setChanged();`

`notifyObservers();`

`}`

`public` `String getFullName() {`

`return` `mFullName;`

`}`

`public` `int` `getAge() {`

`return` `mAge;`

`}`

`}`

现在我们已经重构了我们的类以使用 Java 可观察 API,让我们看看与以前的版本相比发生了什么变化。首先要注意的是,我们正在扩展一个超类(这意味着这个类不能扩展任何其他类),而不是像我们在上一节中所做的那样实现接口。

我们不再举行观察员会议,而是举行观察员会议。这是在超类中处理的。同样,我们不必担心观察员的注册,删除或通知 - 正在为我们处理所有这些问题。

另一个区别是,在这个课程中,我们采用了拉动风格。我们提醒观察者发生了更改,但观察者需要使用我们在此类中定义的字段 getter 来提取数据。如果要改用 push 样式,则可以使用该方法并将更改的数据传递给对象参数中的观察者。

超类的方法将一个标志设置为 true,指示数据已更改。然后,您可以调用该方法。请注意,如果您在呼叫之前未呼叫,则不会通知旁听者。您可以使用该方法检查此标志的值,并将其清除回 false 与 。现在我们已经创建了可观察类,让我们看看如何设置观察者。

2. 创建观察点

我们的可观察类需要一个相应的 Observer才能有用,所以让我们重构我们来实现接口。


`import` `android.os.Bundle;`

`import` `android.support.v7.app.AppCompatActivity;`

`import` `android.widget.TextView;`

`import` `com.chikeandroid.tutsplusobserverpattern.R;`

`import` `java.util.Observable;`

`import` `java.util.Observer;`

`public` `class` `UserProfileActivity` `extends` `AppCompatActivity` `implements` `Observer {`

`private` `Observable mUserDataRepositoryObservable;`

`private` `TextView mTextViewUserFullName;`

`private` `TextView mTextViewUserAge;`

`@Override`

`protected` `void` `onCreate(Bundle savedInstanceState) {`

`super``.onCreate(savedInstanceState);`

`setContentView(R.layout.activity_user_profile);`

`mTextViewUserAge = (TextView) findViewById(R.id.tv_age);`

`mTextViewUserFullName = (TextView) findViewById(R.id.tv_fullname);`

`mUserDataRepositoryObservable = UserDataRepository.getInstance();`

`mUserDataRepositoryObservable.addObserver(``this``);`

`}`

`@Override`

`public` `void` `update(Observable observable, Object o) {`

`if` `(observable` `instanceof` `UserDataRepository) {`

`UserDataRepository userDataRepository = (UserDataRepository)observable;`

`mTextViewUserAge.setText(String.valueOf(userDataRepository.getAge()));`

`mTextViewUserFullName.setText(userDataRepository.getFullName());`

`}`

`}`

`@Override`

`protected` `void` `onDestroy() {`

`super``.onDestroy();`

`mUserDataRepositoryObservable.deleteObserver(``this``);`

`}`

`}`

在该方法中,我们通过使用超类中的方法将此类作为观察者添加到可观察量中。

在观察者必须实现的方法中,我们检查作为参数接收的是否是我们的实例(请注意,观察者可以订阅不同的可观察量),然后将其转换为该实例并使用字段检索我们想要的值。然后,我们使用这些值来更新视图小部件。

当活动被销毁时,我们不需要从可观察量中获取任何更新,因此我们只需通过调用方法从观察者列表中删除活动即可。

相关文章

网友评论

      本文标题:安卓设计模式之观察者模式

      本文链接:https://www.haomeiwen.com/subject/tkqxzrtx.html