ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Observer
    Modeling/DesignPattern 2020. 2. 24. 22:01

    1. Overview

    Observer pattern is used when there is a one-to-many relationship between objects such as if one object is modified, its dependent objects are to be notified automatically. Observer pattern falls under the behavioral pattern category. We are defining one-to-many dependency between objects, where many objects are listening for the state change of a single object, without tightly coupling all of them together. This pattern is often implemented where the listener only gets a notification that "something" has changed in the object's state. Listeners query back to find out more information if needed. This makes it more generic as different listeners may be interested in different states. This design pattern is also called as publisher-subscriber or pub-sub.

    2. Description

    2.1 Implement Observer

    • We define an interface for observer. Observer is usually a very simple interface and defines a method used by "subject" to notify about a state change
    • Subject can be an interface if we are expecting our observers to listen to multiple objects or else subject can be any concrete class
    • Implementing subject means taking care of handling attach, detach of observers, notifying all registered observers and providing methods to provide state information requested by observers.
    • Concrete observers use a reference passed to them to call subject for getting more information about the state. If we are passing changed state in notify method then this is not required.

    2.2 Consideration

    2.2.1 Implementation

    • Watch for Infinite circular
    • It becomes quite easy to identify originator for the notification if subjects pass a reference to themselves in notification to the observer
    • Performance can become an issue if number of observers is higher and if one or many of them need a noticeable time to process notification.

    2.2.2 Design

    • To reduce number of notifications sent on each state update, we can also have observers register for a specific property or event. This improves performance as on an event, subject notifies only the interested observers instead of all registered observers.
    • Typically notifications are sent by observable when someone changes its state, but we can also make the client code, which is changing subject's state, send notification too. This way we get notification when all state changes are done. However, client node gets this additional responsibility which they may forget to carry out.

    2.3 Pitfalls

    • Every setter method triggering updates may be too much if we have client setting properties one after another on our observable
    • Also, each update becomes expensive as the number of observers increase and we have one or more slow observers in the list
    • If observers call back the subject to find what changed then this can add up to quite a bit of overhead

    3. Usage

    3.1 Java Servlet Application

    We can create various listeners by implementing interfaces like HttpSessionListener, ServletRequestListener. We then register these listeners with ServletContext's addListener method.

    4. Comparison with Mediator

    Observer Mediator
    Provides with a one-to-many relationship between objects Mediators have many objects communicating with many other objects
    The communication is simple and can be described as a publish-subscribe Communication is not simple. All objects participating are notified of a change in any one of them

    5. Example

    interface OrderObserver {
        void updated(Order order);
    }
    class PriceObserver implements OrderObserver {
        @Override
        public void updated(Order order) {
            double total = order.getItemCost();
    
            if(total >= 200) {
                order.setDiscount(10);
            } else if(total >= 500) {
                order.setDiscount(20);
            }
        }
    }
    class QuantityObserver implements OrderObserver {
        @Override
        public void updated(Order order) {
            int count = order.getCount();
            if(count <= 5) {
                order.setShippingCost(10);
            } else {
                order.setShippingCost(10 + (count - 5) * 1.5);
            }
        }
    }
    
    class Order {
        private String id;
        private double itemCost;
        private int count;
        private double discount;
        private double shippingCost;
        private List<OrderObserver> observers = new ArrayList<>();
        public Order(String id) {
            this.id = id;
        }
    
        public void attach(OrderObserver observer) {
            observers.add(observer);
        }
        public void detach(OrderObserver observer) {
            observers.remove(observer);
        }
    
        public double getItemCost() {
            return itemCost;
        }
    
        public int getCount() {
            return count;
        }
    
        public double getDiscount() {
            return discount;
        }
    
        public void setDiscount(double discount) {
            this.discount = discount;
        }
    
        public double getTotal() {
            return itemCost - discount + shippingCost;
        }
    
        public double getShippingCost() {
            return shippingCost;
        }
    
        public void setShippingCost(double shippingCost) {
            this.shippingCost = shippingCost;
        }
    
        public void addItem(double price) {
            itemCost += price;
            count++;
            observers.forEach(o -> o.updated(this));
        }
    
        @Override
        public String toString() {
            return "Order [id=" + id + ", itemCost=" + itemCost+", count="
                    +count+", discount="+discount+", shippingCost="+shippingCost+"]";
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            Order order = new Order("100");
            PriceObserver price = new PriceObserver();
            order.attach(price);
            order.addItem(50);
            System.out.println(order);
        }
    }

    4. Reference

    https://www.tutorialspoint.com/design_pattern/observer_pattern.htm

    'Modeling > DesignPattern' 카테고리의 다른 글

    Prototype  (0) 2020.02.26
    Facade  (0) 2020.02.24
    Builder  (0) 2020.02.24
    Singleton  (0) 2020.02.24
    Model–view–controller (MVC)  (0) 2020.02.23

    댓글

Designed by Tistory.