Android Design Patterns: The Observer Pattern
Observer Pattern là gì ? Observer Pattern là một design pattern thiết lập sự phụ thuộc một-nhiều giữa các đối tượng. Bất cứ khi nào trạng thái của một trong các đối tượng ("subject" hoặc "observable") thay đổi, tất cả các đối tượng khác ("observers") phụ thuộc vào nó sẽ được thông báo. Lợi ích ...
Observer Pattern là gì ?
Observer Pattern là một design pattern thiết lập sự phụ thuộc một-nhiều giữa các đối tượng. Bất cứ khi nào trạng thái của một trong các đối tượng ("subject" hoặc "observable") thay đổi, tất cả các đối tượng khác ("observers") phụ thuộc vào nó sẽ được thông báo.
Lợi ích của Observer Pattern
- Subject ít biết về các observers của nó. Điều duy nhất nó biết là các observers thực hiện hoặc đồng ý với một interface nhất định.
- Các Subjects có thể được sử dụng lại mà không có sự tham gia của các observers, và cũng tương tự đối với các observers.
- Không sửa đổi nào được thực hiện cho đối tượng để chứa một observer mới. Observer mới chỉ cần thực hiện một interface mà Subject nhận thức được và sau đó đăng ký tới subject.
- Một observer có thể được đăng ký cho nhiều subject mà nó được đăng ký.
Xây dựng Observer Pattern
1. Tạo Subject Interface
Chúng ta bắt đầu bằng việc định nghĩa một interface mà các Subject ( observables ) sẽ implement :
public interface Subject { void registerObserver(RepositoryObserver repositoryObserver); void removeObserver(RepositoryObserver repositoryObserver); void notifyObservers(); }
Trong đoạn code trên, chúng ta tạo ra một Java Interface với 3 phương thức. Phương thức đầu tiên registerObserver(), như tên gọi của nó, sẽ đăng kí một observer kiểu dữ liệu RepositoryObserver ( chúng ta sẽ tạo interface này sau ) tới subject. Phương thức removeObserver() sẽ được gọi để xóa bỏ một observer mà muốn dừng nhận thông báo từ subject. Và cuối cùng, phương thức notifyObserver() sẽ gửi một broadcast tới tất cả các observers bất cứ khi nào có sự thay đổi.
Bây giờ, chúng ta hãy tạo ra một lớp cụ thể mà sẽ implement từ interface chúng ta đã tạo ra:
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(); } }
Lớp trên implement từ interface Subject. Chúng ta có một ArrayList giữ các observers và sau đó tạo một hàm khởi tạo. Một observer đăng kí bằng cách thêm vào ArrayList và tương tự như vậy, hủy bỏ đăng kí bằng cách xóa khỏi ArrayList.
Lưu ý rằng, chúng ta đang mô phỏng một request mạng để lấy về dữ liệu mới. Một khi phương thức setUserData() được gọi và đưa ra giá trị mới cho name và age, chúng ta sẽ gọi phương thức notifyObservers(), như tên gọi của nó, nó sẽ gửi thông báo tới tất cả các observers đã đăng kí lắng nghe về sự thay đổi dữ liệu mới này.
Các giá trị mới cho name và age cũng sẽ được truyền qua. Subject này có thể có nhiều observers, nhwung trong hướng dẫn này, chúng ta sẽ chỉ tạo ra một observer, nhưng trước tiên hãy tạo ra interface observer.
2. Tạo Create the Observer Interface
public interface RepositoryObserver { void onUserDataChanged(String fullname, int age); }
Trong đoạn code trên, chúng ta đã ra một observer interface mà các observers cụ thể cần được implement. Điều này làm cho code của chúng ta linh hoạt hơn bởi vì chúng ta đang coding một interface thay vì code một implement cụ thể.
Một lớp subject cụ thể không cần có nhiều observers. Tất cả những gì nó biết về chúng là chúng đã implement từ RepositoryObserver.
Hãy tạo ra một lớp cụ thể mà implement từ interface này :
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); } }
Điều đầu tiên chúng ta cần chú ý trong đoạn code trên là activity UserProfileActivity đã implement từ RepositoryObserver - vì vậy, nó phải implement phương thức onUserDataChanged(). Trong phương thức onCreate() của activity, chúng ta có một instance của UserDataRepository, khởi tạo và đăng kí nó với observer.
Trong phương thức onDestroy(), chúng ta muốn ngừng nhận thông báo, cho nên chúng ta hủy đăng kí nhận thông báo.
Trong hàm onUserDataChanged(), chúng ta sẽ cập nhật thay đổi các giá trị mới lên TextView - mTextViewUserFullName và mTextViewUserAge.