“Design Pattern ii – Observer Pattern”

This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together

First, reply TO TD unsubscribe

In daily life, this kind of SMS is everywhere, all kinds of advertisements, in the rapid development of the Internet today, personal information can be said to be transparent. There is no privacy at all, and notifications like this follow the Observer Pattern we use during development. It is more appropriate to subscribe to the weekly newspaper of English learning when I was in junior high school. Most of a class will subscribe to the weekly newspaper basically. This is the typical observer pattern, publish-subscribe. Publishers+Subscribers=Obeserver Pattern. A one-to-many relationship like this, in which an object’s state changes and all subscribed objects are notified and perform some of their own operations, can be explained by the observer pattern.

Ii. Obeserver Pattern of observers

Subscribers receive notifications and perform actions (updating their own state or behavior) when the state of the Publishers changes (Subscribers). Observer mode is an object behavior mode.

Three, components

Take the above:

  • You need an abstract Subject, such as this one, for intuitive thinking. You need to store all Observers, so that they are guaranteed to be distributed to every student. If you want to delete students who are not subscribing (Observers), you can also add students who want to subscribe (Observers).

    The publisher Subject needs to hold all subscribers and provide methods for adding and deleting subscriptions, and abstract methods for notifying subscribers of their state changes (Notify).

  • An Observser is needed, in this case the student can act as a subscriber, in this case it can be abstracted as an Observer, in a more general way, the teacher can also subscribe, and other people who need it can also subscribe. An Observer can be understood as an abstraction of a role.

    A subscriber Observer is an abstract interface or abstract class (commonly called an interface) that provides abstract methods for updating its own behavior, or properties

  • Concrete Observer is required. As mentioned earlier, students are just one of many subscription types. Anyone who needs them can subscribe.

  • The same Concrete Subject is the Concrete realization of Subject, and the benefits are needless to say, which is why we need to understand six basic design principles at the beginning of learning design patterns. Abstraction does not depend on implementation details. Details should depend on abstractions, which constrain details and make them more formal and controllable.

  • Structure:

Four, code implementation
1. Design a price change system

There are many fruits in the fruit store, and seasonal fruits are usually very expensive, such as cherries in this season now (cherries free 🍒 has not been realized), fruits that are not easy to preserve, strawberries and so on. The price is unified management and distributed to each store.

  • The themeSubject, that is, the publisher
/** * Created by Sai * on: 10/01/2022 11:41. * Description: */
public abstract class Subject {

  private final Logger logger = Logger.getLogger(Subject.class.getName());
  /** Saves a collection of subscriber objects */
  private final List<Observer> observerList = new CopyOnWriteArrayList<>();

  /** New subscriber Observer */
  public boolean attach(Observer observer) {
    logger.info(observer + "Added successfully");
    return observerList.add(observer);
  }

  /** Unbind the subscriber */
  public boolean detach(Observer observer) {
    logger.info(observer + "Unbound successful");
    return observerList.remove(observer);
  }

  /** Updates notifications to Observers */
  protected void notifyObservers(a) {
    if (observerList.isEmpty()) {
      return;
    }
    for (Observer observer : observerList) {
      observer.priceChanged(this); }}}Copy the code
  • Concrete implementation classes – such as cherries
/** * Created by Sai * on: 10/01/2022 12:16. * Description: */
public class Cherry extends Subject {
  / * * * / price
  private long price;

  / * * name * /
  private String name;

  public Cherry(String name) {
    this.name = name;
  }

  public String getName(a) {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public long getPrice(a) {
    return price;
  }

  public void setPrice(long price) {
    /** Notify all stores of price changes */
    this.price = price;
    notifyObservers();
  }

  @Override
  public String toString(a) {
    return "Cherry{" + "price=" + price + ", name='" + name + '\' ' + '} '; }}Copy the code
  • Defining the observerObserverinterface
/** * Created by Sai * on: 10/01/2022 11:34. * Description: */
public interface Observer {
  	// This is a topic
    void priceChanged(Subject subject);
}
Copy the code
  • Concrete implementation class – Store Store
/** * Created by Sai * on: 10/01/2022 12:22. * Description: */
public class Store implements Observer {

    private String storeName;

    public Store(String storeName) {
        this.storeName = storeName;
    }

    public String getStoreName(a) {
        return storeName;
    }

    public void setStoreName(String storeName) {
        this.storeName = storeName;
    }

    private void show(Subject subject) {
        System.out.println(this.storeName + subject.toString());
    }

    @Override
    public void priceChanged(Subject subject) {
        System.out.println(this.storeName);
        System.out.println("Price Changed - Refreshing price");
        show(subject);
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- >"); }}Copy the code
  • The test case
/** * Created by Sai * on: 10/01/2022 12:27. * Description: */
public class Demo {

  public static void main(String[] args) {
    Cherry cherry = new Cherry("Cherry");
    Store one = new Store("Store one");
    Store two = new Store("Store two");

    cherry.attach(one); cherry.attach(two);
    cherry.setPrice(100);
    // The price is up
    cherry.setPrice(200);
    // The store went out of business
    cherry.detach(one);
    cherry.setPrice(99); }}Copy the code
  • The print information
Information: com.observer.sai.Store@2f92e0f4 Added successfully1month10.2022 1:01:22Afternoon com.observer.sai.Subject Attach Information: com.observer.sai.Store@4f3f5b24 Added successfully1month10.2022 1:01:22Afternoon com.observer.sai.Subject detach information: com.observer.sai.Store@2f92e0f4 unbind successful store one Price changed-refreshing Price store one Cherry{Price =100, name='Cherry'} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- > store two Price Changed - Refreshing Price stores two Cherry {Price =100, name='Cherry'} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- > store a Price Changed - Refreshing Price stores a Cherry {Price =200, name='Cherry'} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- > store two Price Changed - Refreshing Price stores two Cherry {Price =200, name='Cherry'} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- > store two Price Changed - Refreshing Price stores two Cherry {Price =99, name='Cherry'}
---------------------------------------->
Process finished with exit code 0
Copy the code
2. Some thinking

Store management system, the realization of the fruit price changes when dynamic information to each store below, the dynamic linkage relationship; Whenever the state or behavior of the subject object changes. Then subscribers perceive this change and act accordingly. Although there is a certain degree of coupling, but also at the level of abstraction, the coupling degree is relatively low, scalability has been guaranteed. The design is designed to solve these problems: reduce coupling, improve cohesion, scalability, and hierarchy.

  • Reduced the publisher (Publishers) and subscribers (Subscribers) degree of direct coupling between abstractions.
  • The dynamic linkage between publishers and subscribers is realized, and subscribers make their own changes to the changes of publishers’ behaviors.

Of course, the disadvantages are also obvious, as can be seen from the example, with the expansion of stores, the depth of system call will increase. Secondly, the closure of stores is too late to untie, which also leads to some unnecessary notices, increasing the burden of the system.

  • Instant subscription and instant unbinding, the former will cause the notification is not in place, miss important information; The latter creates unnecessary notifications.
  • If there is an interdependence, then there will beInfinite loopOf course, in this case, the first thing to think about isObserver modelIs it really appropriate to use at this time?
5. Practical problems

In the current work of the subject owner, there are many scenarios using Observer Pattern. In the shopping cart module business, when the goods are added to the shopping cart, the total price changes, the red dot quantity information of the number of goods changes, the inventory of goods, and The Times of individual goods being purchased all change. Otherwise delete goods likewise.

public interface OnCartObserver {...void onDeleteProduct(int position, int needUpdateCount);
  void onUpdateProduct(int position, CartProductVO product);
  void onCartClear(a);
  // Update of remarks
  void onRemarkUpdate(String[] remarks); . }public abstract class BaseOnCartObserver implements OnCartObserver {...@Override
  public void onDeleteProduct(int position, int needUpdateCount) {}@Override
  public void onCartClear(a) {}@Override
  public void onRemarkUpdate(String[] remarks) {}@Override
  public void onUpdateProduct(int position, CartProductVO product) {}... }// The invocation takes the form of an anonymous inner class and does not strictly follow the observer pattern UML implementation
public class CartGoodsFragment extends BaseFragment {
  private final OnCartObserver onCartObserver = new BaseOnCartObserver() {
    // Update the behavior
  }
  
  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    XX.provideController.addObserver(onCartObserver);
  }
  
  @Override
  public void onDestroy(a) {
    super.onDestroy(); XX.provideController.removeObserver(onCartObserver); }}Copy the code

Strictly speaking, this is not the standard observer mode, but the essence of the observer mode is one-to-many. When the topic state changes, the dependent will immediately perceive and respond to it. In popular terms, it is the starting linkage effect.

Back to the essence of design, design is designed to reduce coupling, reduce complexity, and increase scalability. There is no formula for design, and if you try to copy it completely, it will not only backfire, but also make the project look different. Design for design’s sake is not desirable. What matters is a thoughtful understanding. Actual business and function are ever-changing. Thinking is the most important for the abstract ability of business, and design pattern is only a means to transform ideas into details.

Six, when to use
  • There exists between abstract modelsMore than a pair ofWhen a change in the subject causes changes in other dependents.
  • Need to beDynamic linkageAnd build the system with the lowest possible coupling degree.