ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Mediator
    Modeling/DesignPattern 2020. 3. 1. 19:07

    1. Overview

    • Mediator encapsulates how a set of objects interact with each other. Due to this encapsulation, there is a loose coupling between the interacting objects.
    • Typically an object explicitly knows about other objects to which it wants to interact i.e. to call a method. In mediator pattern this interaction is within the mediator object and interacting objects only know about the mediator object.
    • The benefit of this arrangement is that the interactions can now change without needing modifications to participating objects. Changing the mediator allows adding/removing participants in an interaction.

    2. Description

    2.1 Implementation

    • Mediators define a generic method which is called by other objects
    • This method typically needs to know which object changed and optionally the exact property which has changed in that object
    • We implement this method in which we notify rest of the objects about the state change
    • Mediator needs to know about all participants in the collaboration it is mediating. To solve this problem we can either have objects register with mediator or mediator itself can be the creator of these objects.
    • Depending upon your particular implementation you may need to handle the infinite loop of change-notify-change which can result if object's value change handler is called for every value change whether from an external source as well as the mediator

    2.2 Consideration

    2.2.1 Implementation

    • It's important that mediator can identify which object has sent change notification to avoid sending that object the changed value again
    • If an object method took a very long time to process the change it can affect overall performance of mediator severely. In fact, this is a common problem in any notification system, so pay attention to synchronization in mediator methods.
    • We often end up with a complex mediator since it becomes a central point which ends up handling all routing between objects. This can make it very difficult to maintain the mediator as the complexity grows.

    2.2.2 Design

    • We can extend a mediator and create variations to be used in different situations like platform-dependent interactions
    • Abstract mediator is often not required if the participating objects only work with that one mediator
    • We can use observer design pattern to implement the notification mechanism through which objects notify the mediator

    2.3 Pitfalls

    • Mediator becomes a central control object. As complexity of interaction grows, mediator complexity can quickly get out of hand
    • Making a resuable mediator, one which can be used with multiple sets of different objects is quite difficult. They are typically very specific to the collaboration. Another competing pattern called Observer is much more reusable.

    3. Usage

    • javax.swing.ButtonGroup class. It takes care of making sure that the only button in a group is selected. Participating Buttons notify this mediator when they are selected.
    • The DispatcherServlet in Spring

    4. Comparison with Observer

    Mediator Observer
    Intent is to encapsulate complex interaction between objects Intent is to define one-to-many relationship between objects
    Mediator implementations are typically specific to objects being mediated Observer pattern implementations are generic. Once implemented it can be used with any classes.

    5. Example

    //Mediator
    class UIMediator {
        List<UIControl> colleagues = new ArrayList<>();
        public void register(UIControl control) {
            colleagues.add(control);
        }
        public void valueChanged(UIControl control) {
            colleagues.stream().filter(c -> c != control).forEach(c -> c.controlChanged(control));
        }
    }
    //Abstract colleague
    interface UIControl {
        void controlChanged(UIControl control);
        String getControlValue();
        String getControlName();
    }
    class TextBox extends TextField implements UIControl{
        private UIMediator mediator;
        private boolean mediateUpdate;
        public TextBox(UIMediator mediator) {
            this.mediator = mediator;
            this.setText("Textbox");
            this.mediator.register(this);
            this.textProperty().addListener((v, o, n) -> {
                if(!mediateUpdate)
                    this.mediator.valueChanged(this);
            });
        }
    
        @Override
        public void controlChanged(UIControl control) {
            this.mediateUpdate = true;
            this.setText(control.getControlValue());
            this.mediateUpdate = false;
        }
    
        @Override
        public String getControlValue() {
            return getText();
        }
    
        @Override
        public String getControlName() {
            return "Textbox";
        }
    }
    class Slider extends javafx.scene.control.Slider implements UIControl{
    
    	private UIMediator mediator;
    	private boolean mediatedUpdate;
    
    	public Slider(UIMediator mediator) {
    		this.mediator = mediator;
    		setMin(0);
    		setMax(50);
    		setBlockIncrement(5);
    		mediator.register(this);
    		this.valueProperty().addListener((v,o,n) ->{if(!mediatedUpdate) this.mediator.valueChanged(this);});
    	}
    
    	@Override
    	public void controlChanged(UIControl control) {
    		mediatedUpdate = true;
    		setValue(Double.valueOf(control.getControlValue()));
    		mediatedUpdate = false;
    	}
    
    	@Override
    	public String getControlName() {
    		return "Slider";
    	}
    
    	@Override
    	public String getControlValue() {
    		return Double.toString(getValue());
    	}
    
    
    }
    class Label extends javafx.scene.control.Label implements UIControl{
    
    	private UIMediator mediator;
    
    	public Label(UIMediator mediator) {
    		this.mediator = mediator;
    		this.setMinWidth(100);
    		this.setText("Label");
    		mediator.register(this);
    	}
    
    	@Override
    	public void controlChanged(UIControl control) {
    		setText(control.getControlValue());
    	}
    
    	@Override
    	public String getControlValue() {
    		return getText();
    	}
    
    	@Override
    	public String getControlName() {
    		return "Label";
    	}
    
    
    }
    public class Client extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
    		UIMediator mediator = new UIMediator();
    		Slider slider = new Slider(mediator);
    		TextBox box = new TextBox(mediator);
    		Label label = new Label(mediator);
    
    		GridPane grid = new GridPane();
    		grid.setAlignment(Pos.CENTER);
    		grid.setVgap(20);
    		grid.setPadding(new Insets(25, 25, 25, 25));
    		grid.add(label, 0, 0);
    		grid.add(slider, 0, 1);
    		grid.add(box, 0, 2);
    		Scene scene = new Scene(grid, 500, 500);
    		primaryStage.setTitle("Mediator Pattern");
    		primaryStage.setScene(scene);
    		primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }

    6. Reference

    https://en.wikipedia.org/wiki/Mediator_pattern

    https://courseprobe.com/instructors/coffee-powered-crew/

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

    Flux  (0) 2020.04.11
    Model View Presenter (MVP)  (0) 2020.04.10
    Memento  (0) 2020.03.01
    Composite  (0) 2020.02.29
    Chain of responsibility  (0) 2020.02.29

    댓글

Designed by Tistory.