diff --git a/memento/README.md b/memento/README.md index 1bf6e442bb0f6de1d3a87ae98704daa6d34323d4..8011dfc493740e89809e12d909a63366458c52d5 100644 --- a/memento/README.md +++ b/memento/README.md @@ -12,8 +12,177 @@ tags: Token ## Intent -Without violating encapsulation, capture and externalize an -object's internal state so that the object can be restored to this state later. +Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored +to this state later. + +## Explanation +Real world example + +> We are working on astrology application where we need to analyze star properties over time. We are creating snapshots of star state using Memento pattern. + +In plain words + +> Memento pattern captures object internal state making it easy to store and restore objects in any point of time. + +Wikipedia says + +> The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback). + +**Programmatic Example** + +Let's first define the types of stars we are capable to handle. + +```java +public enum StarType { + + SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD( + "dead star"), UNDEFINED(""); + + private String title; + + StarType(String title) { + this.title = title; + } + + @Override + public String toString() { + return title; + } +} +``` + +Next let's jump straight to the essentials. Here's the star class along with the mementos that we need manipulate. + +```java +public interface StarMemento { +} + +public class Star { + + private StarType type; + private int ageYears; + private int massTons; + + public Star(StarType startType, int startAge, int startMass) { + this.type = startType; + this.ageYears = startAge; + this.massTons = startMass; + } + + public void timePasses() { + ageYears *= 2; + massTons *= 8; + switch (type) { + case RED_GIANT: + type = StarType.WHITE_DWARF; + break; + case SUN: + type = StarType.RED_GIANT; + break; + case SUPERNOVA: + type = StarType.DEAD; + break; + case WHITE_DWARF: + type = StarType.SUPERNOVA; + break; + case DEAD: + ageYears *= 2; + massTons = 0; + break; + default: + break; + } + } + + StarMemento getMemento() { + + StarMementoInternal state = new StarMementoInternal(); + state.setAgeYears(ageYears); + state.setMassTons(massTons); + state.setType(type); + return state; + } + + void setMemento(StarMemento memento) { + + StarMementoInternal state = (StarMementoInternal) memento; + this.type = state.getType(); + this.ageYears = state.getAgeYears(); + this.massTons = state.getMassTons(); + } + + @Override + public String toString() { + return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons); + } + + private static class StarMementoInternal implements StarMemento { + + private StarType type; + private int ageYears; + private int massTons; + + public StarType getType() { + return type; + } + + public void setType(StarType type) { + this.type = type; + } + + public int getAgeYears() { + return ageYears; + } + + public void setAgeYears(int ageYears) { + this.ageYears = ageYears; + } + + public int getMassTons() { + return massTons; + } + + public void setMassTons(int massTons) { + this.massTons = massTons; + } + } +} +``` + +And finally here's how we use the mementos to store and restore star states. + +```java + Stack states = new Stack<>(); + Star star = new Star(StarType.SUN, 10000000, 500000); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + while (states.size() > 0) { + star.setMemento(states.pop()); + LOGGER.info(star.toString()); + } + + // sun age: 10000000 years mass: 500000 tons + // red giant age: 20000000 years mass: 4000000 tons + // white dwarf age: 40000000 years mass: 32000000 tons + // supernova age: 80000000 years mass: 256000000 tons + // dead star age: 160000000 years mass: 2048000000 tons + // supernova age: 80000000 years mass: 256000000 tons + // white dwarf age: 40000000 years mass: 32000000 tons + // red giant age: 20000000 years mass: 4000000 tons + // sun age: 10000000 years mass: 500000 tons +``` + ## Class diagram ![alt text](./etc/memento.png "Memento")