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

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

作者: 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