Skip to content

Instantly share code, notes, and snippets.

@billy-idle
Last active November 30, 2018 06:27
Show Gist options
  • Save billy-idle/115dabd9c27dd4ae7805e6e9b23e306b to your computer and use it in GitHub Desktop.
Save billy-idle/115dabd9c27dd4ae7805e6e9b23e306b to your computer and use it in GitHub Desktop.
MVC "Push" Pattern from scratch.
package mvc.from.scratch.push;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
interface Observer<T> {
void update(T t);
}
public class MVCPushFromScratch {
public static void main(String[] args) {
// The Model doesn't know anything about the controller neither the view.
var rnm = new RandomNumberModel();
// The Controller knows about the Model but not the View.
var rnc = new RandomNumberController(rnm);
// The View only knows about the Controller.
// The Model is pushing its data trough the Observer interface
var rnv = new RandomNumberView(rnc);
// The Model registers the View
rnm.registerObserver(rnv);
int i = 0;
while (i < 5) {
/*
Imagine that this could be an ActionEvent
triggered by some Button. i.e. "generateRandomNumberButton"
*/
rnv.generateRandomNumber();
i++;
}
/*
Output
1. 66
2. 17
3. 75
4. 94
5. 39
*The output will vary because its randomness.
*/
}
}
abstract class Subject<T> {
private List<Observer<T>> observers = new ArrayList<>();
public void registerObserver(Observer<T> o) {
observers.add(o);
}
public void removeObserver(Observer<T> o) {
observers.remove(o);
}
protected void notifyObservers(T t) {
observers.forEach(o -> o.update(t));
}
public void removeAllObservers() {
observers.clear();
}
}
/**
* In general, in the MVC pattern all the dependencies point to the Model.
* The Model doesn't know anything about the controller neither the view.
*/
class RandomNumberModel extends Subject<Integer> {
private Random random;
public RandomNumberModel() {
this.random = new Random();
}
/**
* Generates an integer random number between 0 and 100,
* notifying and broadcasting its state to all the observers.
*/
public void generateRandomNumber() {
var number = this.random.nextInt(101);
notifyObservers(number);
}
}
/**
* The Controller knows about the Model but not the View.
* Its main purpose is to send commands from the View to the Model.
* ("Commands" change the state of the system and return nothing)
*/
class RandomNumberController {
private RandomNumberModel rnm;
public RandomNumberController(RandomNumberModel rnm) {
this.rnm = rnm;
}
/**
* Encapsulates the call. ("Tell", don't "Ask" Principle)
*/
public void generateRandomNumber() {
this.rnm.generateRandomNumber();
}
}
/**
* The View knows about the Controller but not the Model, or, at least
* the data type that is being pushed.
*/
class RandomNumberView implements Observer<Integer> {
private RandomNumberController rnc;
private int position;
private int number;
public RandomNumberView(RandomNumberController rnc) {
this.rnc = rnc;
}
public void generateRandomNumber() {
this.rnc.generateRandomNumber();
}
/**
* This is call when the Model calls notifyObservers()
*/
public void update(Integer t) {
this.number = t;
this.updatePosition();
this.printRandomNumber();
}
private void updatePosition() {
this.position++;
}
private void printRandomNumber() {
System.out.printf("%-1d. %s%n", this.position, this.number);
}
}
@billy-idle
Copy link
Author

billy-idle commented Nov 26, 2018

Class Diagram - MVC "Push" Pattern From Scratch

mvcpushfromscratch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment