110
1 DESIGN PATTERNS BY RENAUD HOYOUX

Mieux programmer grâce aux design patterns

Embed Size (px)

Citation preview

1

DESIGN PATTERNS

BY

RENAUD HOYOUX

2 . 1

ABOUT MEArchitect on Cytomine.

2 . 2

Benevolent Dictator of the non-prot organization KodoWallonie.

ABOUT ME

2 . 3

Coach at CoderDojo Liège.

ABOUT ME

3

DESIGN PATTERNSIn software engineering, a design pattern is a general

repeatable solution to a commonly occurring problem insoftware design. A design pattern isn't a nished design thatcan be transformed directly into code. It is a description or

template for how to solve a problem that can be used in manydifferent situations.

4 . 1

OBJECT ORIENTED PROGRAMMINGInheritanceCompositionPolymorphism

4 . 2

INHERITANCEclass Sandwich private int weight; public void eat() System.out.println("Miam"); public void buy() System.out.println("it costs X euros");

class GASandwich extends Sandwich public void share() System.out.println("I always share when it's not mine");

@Override public void buy() System.out.println("Free as in beer not as in speech");

GASandwich tuna = new GASandwich();tuna.buy();tuna.share();//I can call eat because I inherit from the Sandwich classtuna.eat();

4 . 3

has-a relationship in classes.

COMPOSITION

public class GAEvent private List<GASandwich>; // ...

Every (good) GAEvent has GASandwiches.

4 . 4

POLYMORPHISMSandwich ham = new GASandwich();ham.eat();ham.buy();// but I can't call ham.share();

public void doTheRightThing(Sandwich food) food.buy(); food.eat();

Sandwich ham = new GASandwich();// Yep ! It's workdoTheRightThing(ham);

5

GANG OF FOURCreationnal patterns : Singleton, Factory Method, Abstract Factory, Prototype,Builder.Structural patterns : Proxy, Flyweight, Bridge, Facade, Decorator, Adapter,Composite.Behavioral patterns : Observer, Template Method, Command, Iterator, State,Mediator, Strategy, Chain of Responsibility, Visitor,Interpreter, Memento.

6

GANG OF FOURCreationnal patterns : Singleton, Factory Method, Abstract Factory, Prototype,Builder.

7 . 1

Ensure a class only has one instance, and provide a globalpoint of access to it.

SINGLETON

7 . 2

public class Singleton private static Singleton singleton;

//prevent the use of the new keyword private Singleton()

public static synchronized Singleton getSingleton() if(singleton == null) singleton = new Singleton(); return singleton;

7 . 2

7 . 3

Java Optimisation : Bill Pugh Singleton Implementation

public class BillPughSingleton

private BillPughSingleton() private static class SingletonHelper private static final BillPughSingleton INSTANCE = new BillPughSingleton(); public static BillPughSingleton getInstance() return SingletonHelper.INSTANCE;

8 . 1

Dene an interface for creating an object but let subclassesdecide which class to instanciate. The factory method lets a

class defer instantiation to subclasses.

FACTORY METHOD

8 . 2

Basically, we create object without exposing the creationlogic and refer to newly created object using a common

interface.

8 . 3

interface DatabaseConnector void openConnection(); Result executeQuery(String query); void closeConnection();

public class MySQLConnector implements DatabaseConnector @Override public void openConnection() /* ... */ @Override public Result executeQuery(String query) /* ... */ @Override public void closeConnection() /* ... */ //...

public class PostgreSQLConnector implements DatabaseConnector //...

public class MongoDBConnector implements DatabaseConnector //...

8 . 3

8 . 4

public class DatabaseConnectorFactory

public DatabaseConnector getDatabaseConnector(String database) if(database.equals(DB.MONGO)) return new MongoDBConnector(); else if(database.equals(DB.POSTGRES)) return new PostgreSQLConnector();

else if(database.equals(DB.MYSQL)) return new MySQLConnector();

8 . 4

8 . 5

String database = CONFIG.database;DatabaseConnector connector = factory.getDatabaseConnector(database);connector.openConnection();Result result = connector.executeQuery( "SELECT * sandwiches WHERE NOT rotten");//...connector.closeConnection();

8 . 5

9 . 1

Provides an interface for creating families of related ordependent objects without specifying their concrete classes.

This pattern provides an encapsulation mechanism to a groupof individual factories with a common theme.

ABSTRACT FACTORY

9 . 2

interface DatabaseConnector void openConnection(); Result executeQuery(); void closeConnection();

interface SQLConnector extends DatabaseConnector

interface DocumentOrientedConnector extends DatabaseConnector

9 . 2

9 . 3

public abstract class DatabaseConnectorFactory

String dbHost; int dbPort;

public abstract DatabaseConnector getDatabaseConnector( String database);

9 . 3

9 . 4

public class DocumentOrientedConnectorFactory extends DatabaseConnectorFactory

@Override public DocumentOrientedConnector getDatabaseConnector( String database) if(database.equals(DB.MONGO)) return new MongoDBConnector(); else if(database.equals(DB.COUCHDB)) return new CouchDBConnector();

public class SQLConnectorFactory extends DatabaseConnectorFactory

@Override public SQLConnector getDatabaseConnector(String database) if(database.equals(DB.POSTGRES)) return new PostgreSQLConnector(); else if(database.equals(DB.MYSQL)) return new MySQLConnector();

9 . 4

9 . 5

DatabaseConnectorFactory factory;if(sql) factory = new SQLConnectorFactory(); else factory = new DocumentOrientedConnectorFactory();

DatabaseConnector connector = factory.getDatabaseConnector(database);

connector.openConnection();//...

9 . 5

10 . 1

Specify the kinds of objects to create using a prototypicalinstance, and create new objects by copying this prototype.

PROTOTYPE

10 . 2

public class NPC implements Cloneable //skin, etc. //complex constructor //NB : deep copy is better public Object clone() Object clone = null; try clone = super.clone(); catch (CloneNotSupportedException e) e.printStackTrace(); return clone;

10 . 2

10 . 3

public class NPCCache private static Hashtable<String, NPC> npcMap = new Hashtable<>();

public static NPC getNPC(String id) NPC cachedNPC = npcMap.get(id); return (NPC) cachedNPC.clone();

// Or you can instanciate Objects only when you need them // for the first time. public static void loadCache() NPC npc = new NPC(/* ... */); npcMap.put("walker",npc); //...

10 . 3

10 . 4

NPCCache.loadCache();NPC clonedNPC = NPCCache.getNPC("walker");// change only skin, x, y & dialogs

10 . 4

11 . 1

Separate the construction of a complex object from itsrepresentation so that the same construction processes can

create different representations.

BUILDER

11 . 2

public class Image private byte[] bytes; private ArrayList<MetaData> metadatas; // setters & getters

11 . 2

11 . 3

public abstract class ImageBuilder private byte[] bytes; private ArrayList<MetaData> metadatas; // setters & getters public abstract Image createImage();

11 . 3

11 . 4

public class JpegBuilder extends ImageBuilder public void setCompressionRatio() //...

@Override public Image createImage() //set metadatas & bytes with the good compression & specifications

public class Jpeg2000Builder extends ImageBuilder //...

public class PngBuilder extends ImageBuilder //...

11 . 4

12

GANG OF FOURStructural patterns : Proxy, Flyweight, Bridge, Facade, Decorator, Adapter,Composite.

13 . 1

Provide a surrogate or placeholder for another object tocontrol access to it.

PROXY

13 . 2

We create object having original object to interface itsfunctionality to outer world.

interface Image void display();

13 . 3

public class RealImage implements Image

private String fileName;

public RealImage(String fileName) this.fileName = fileName; loadFromDisk(fileName);

@Override public void display() System.out.println("Displaying " + fileName);

public class ProxyImage implements Image

private RealImage realImage; private String fileName;

@Override public void display() if(realImage == null) realImage = new RealImage(fileName); realImage.display();

13 . 3

13 . 4

Image image = new ProxyImage("test_10mb.jpg");

//image will be loaded from diskimage.display(); System.out.println(""); //image will not be loaded from diskimage.display();

13 . 4

14 . 1

Use sharing to support large numbers of ne grained objectsefciently.

FLYWEIGHT

Flyweight pattern tries to reuse already existing similar kindobjects by storing them and creates new object only when no

matching object is found.

14 . 2

Example : In a Role Playing Game, we have salesman NonPlayable Characters :

They don't move.Event reactions are the same.Only specic caracteristics (prices, items, skin) vary.

14 . 3

public class NPC //skin, etc.

public class SalesmanNPC extends NPC /* ... */

14 . 3

14 . 4

public class NPCFactory private static final HashMap<String, NPC> memo = new HashMap();

public static NPC getNPC(String type) NPC npc = memo.get(type);

if(npc == null) npc = new NPC(/*...*/); // or SalesmanNPC ... memo.put(type, npc); return npc;

14 . 4

14 . 5

SalesmanNPC npc = (SalesmanNPC) NPCFactory.getNPC("salesman");// set X & Y, dialog, itemsnpc.draw();

14 . 5

15 . 1

Decouple an abstraction from its implementation so that thetwo can vary independently

BRIDGE

Prefer composition over inheritance.

15 . 2

15 . 3

interface IColor void fill();

public class Red implements IColor @Override public void fill() System.out.println("fill shape with red color");

public class Green implements IColor @Override public void fill() System.out.println("fill shape with green color");

15 . 3

15 . 4

public abstract class Shape // Composition protected IColor color;

public abstract void draw();

public class Triangle extends Shape @Override public void draw() System.out.print("Draw triangle and ");

public class Square extends Shape @Override public void draw() System.out.print("Draw square and ");

15 . 4

15 . 5

Shape triangle = new Triangle(new Green());triangle.draw();Shape square = new Square(new Red());square.draw();

Draw triangle and fill shape with green colorDraw square and fill shape with red color

15 . 5

16 . 1

Provide a unied interface to a set of interfaces in a system.Facade denes a higher-level interface that makes the

subsystem easier to use. this pattern adds an interface toexisting system to hide its complexities.

FACADE

16 . 2

Facade pattern hides the complexities of the system byinvolving a single class which provides simplied methods

required by client and delegates calls to methods of existingsystem classes.

This is the basic principle of an API...

17 . 1

Attach additionnal responsibilities to an object dynamically.Decorators provide a exible alternative to subclassing for

extending functionality.

DECORATOR

Instead of modifying the existing functionalities, we willextend them.

One class takes in another class, both of which extend thesame abstract class, and adds functionality.

17 . 2

interface Shape void draw();

public class Rectangle implements Shape

@Override public void draw() System.out.println("Shape: Rectangle");

public class Square implements Rectangle

@Override public void draw() System.out.println("Shape: Square");

17 . 2

17 . 3

public abstract class ShapeDecorator implements Shape protected Shape decoratedShape;

public ShapeDecorator(Shape decoratedShape) this.decoratedShape = decoratedShape;

public abstract void draw();

17 . 3

17 . 4

public class RedBorderShape extends ShapeDecorator

public RedBorderShape(Shape decoratedShape) super(decoratedShape);

@Override public void draw() decoratedShape.draw(); setRedBorder(decoratedShape); //...

public class SmoothBorderShape extends ShapeDecorator

public SmoothBorderShape(Shape decoratedShape) super(decoratedShape);

@Override public void draw() decoratedShape.draw(); setSmooothBorder(decoratedShape); //...

17 . 4

17 . 5

//A simple squareShape square = new Square();square.draw();

//A red squareShape redSquare = new RedBorderShape(square);redSquare.draw();

//A rectangle with smooth borderShape smoothRectangle = new SmoothBorderShape(new Rectangle());smoothRectangle.draw();

//Even a red rectangle with smooth borderShape redSmoothRectangle = new SmoothBorderShape( new RedBorderShape( new Rectangle()));redSmoothRectangle.draw();

17 . 5

17 . 6

Real example :

//First open an inputstream of it:FileInputStream fis = new FileInputStream("/objects.gz");

//We want speed, so let's buffer it in memory:BufferedInputStream bis = new BufferedInputStream(fis);

//The file is gzipped, so we need to ungzip it:GzipInputStream gis = new GzipInputStream(bis);

//we can now use the read method.

18 . 1

Convert the interface of a class into another interface thatclient expect. The adapter pattern lets classes work togetherthat couldn't otherwise because of incompatible interfaces.

ADAPTER

18 . 2

interface MediaPlayer void play(String audioType, String fileName);

interface AdvancedMediaPlayer void play(String fileName);

18 . 2

18 . 3

public class VlcPlayer implements AdvancedMediaPlayer @Override public void play(String fileName) System.out.println("Playing vlc file. Name: "+ fileName);

public class Mp4Player implements AdvancedMediaPlayer @Override public void play(String fileName) System.out.println("Playing mp4 file. Name: "+ fileName);

18 . 3

18 . 4

public class MediaAdapter implements MediaPlayer

AdvancedMediaPlayer advancedMusicPlayer;

public MediaAdapter(String audioType) if(audioType.equalsIgnoreCase("vlc") ) advancedMusicPlayer = new VlcPlayer(); else if (audioType.equalsIgnoreCase("mp4")) advancedMusicPlayer = new Mp4Player();

@Override public void play(String audioType, String fileName) advancedMusicPlayer.play(fileName);

18 . 4

18 . 5

public class AudioPlayer implements MediaPlayer MediaAdapter mediaAdapter;

@Override public void play(String audioType, String fileName)

//inbuilt support to play mp3 music files if(audioType.equalsIgnoreCase("mp3")) System.out.println("Playing mp3 file. Name: " + fileName); //mediaAdapter is providing support to play other file formats else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType, fileName); //else ...

18 . 5

18 . 6

AudioPlayer audioPlayer = new AudioPlayer();

audioPlayer.play("mp3", "beyond the horizon.mp3");audioPlayer.play("mp4", "alone.mp4");audioPlayer.play("vlc", "far far away.vlc");audioPlayer.play("avi", "mind me.avi");

18 . 6

19 . 1

Compose objects into tree structures to represent part-whole hierarchies. The composite pattern lets client treatindividual objects and compositions of objects uniformly.

COMPOSITE

19 . 2

Example : File in Java

19 . 3

public class Employee private String name; //... private List<Employee> subordinates = new ArrayList<>();

public void add(Employee e) subordinates.add(e);

public void remove(Employee e) subordinates.remove(e);

public List<Employee> getSubordinates() return subordinates;

19 . 3

20

GANG OF FOURBehavioral patterns : Observer, Template Method, Command, Iterator, State,Mediator, Strategy, Chain of Responsibility, Visitor,Interpreter, Memento.

21 . 1

Dene a one-to-many dependency between objects so thatwhen one object changes state, all its dependents are notied

and updated automatically.

OBSERVER

21 . 2

Example : A Graphical User Interface with 3 visualizations ofa number : binary, octal and hexadecimal. Whenever thenumber changes, these visualizations must change too.

21 . 3

interface IObserver<T> void update(T i);

interface IObservable<T> void attach(IObserver observer); //void remove(IObserver observer); //void clean(); //... public void notifyAllObservers(T state);

21 . 3

21 . 4

class Subject implements IObservable<Integer> private List<IObserver> observers = new ArrayList<IObserver>(); private int state;

public void setState(int state) this.state = state; notifyAllObservers(this.state);

public void attach(IObserver observer) observers.add(observer);

public void notifyAllObservers(Integer state) for (IObserver observer : observers) observer.update(state);

21 . 4

21 . 5

class BinaryObserver implements IObserver<Integer> @Override public void update(Integer i) System.out.println("Binary String: "+Integer.toBinaryString(i));

class HexaObserver implements IObserver<Integer> @Override public void update(Integer i) System.out.println("Hex String: "+Integer.toHexString(i) .toUpperCase());

21 . 5

21 . 6

Subject subject = new Subject();subject.attach(new BinaryObserver());subject.attach(new HexaObserver());

System.out.println("First state change: 15"); subject.setState(15);System.out.println("Second state change: 10"); subject.setState(10);

First state change: 15Binary String: 1111Hex String: F

Second state change: 10Binary String: 1010Hex String: A

21 . 6

21 . 7

A FUNCTIONAL INTERFACE@FunctionalInterfaceinterface IObserver<T> void update(T i);

Subject subject = new Subject();subject.attach(i ­> System.out.println("Binary String: "+Integer.toBinaryString(i)););subject.attach(i ­> System.out.println("Hex String: "+Integer.toHexString(i) .toUpperCase()););

System.out.println("First state change: 15"); subject.setState(15);System.out.println("Second state change: 10"); subject.setState(10);

22 . 1

Dene the skeleton of an algorithm in an operation, deferringsome steps to subclasses. The template method lets

subclasses redene certains steps of an algorithm withoutchanging the algorithm's structure.

TEMPLATE METHOD

22 . 2

Well ... It's the purpose of an abstract class.

23 . 1

Encapsulate a request as an object, thereby letting youparameterize clients with different requests, queue or log

request, and support undoable operations.

COMMAND

23 . 2

Data Driven pattern

23 . 3

class Stock private String name = "ABC"; private int quantity = 10;

public void buy() System.out.println("Stock : "+quantity+" "+name+" bought"); public void sell() System.out.println("Stock : "+quantity+" "+name+" sold");

23 . 3

23 . 4

interface Order void execute();

abstract class StockOrder implements Order protected Stock stock; abstract void execute();

23 . 4

23 . 5

class BuyStock extends StockOrder

public BuyStock(Stock stock) this.stock = stock;

public void execute() stock.buy();

class SellStock extends StockOrder

public SellStock(Stock stock) this.stock = stock;

public void execute() stock.sell();

23 . 5

23 . 6

class Broker private List<Order> orderList = new ArrayList<Order>();

public void takeOrder(Order order) orderList.add(order);

public void placeOrders() for (Order order : orderList) order.execute(); orderList.clear();

Stock abcStock = new Stock();

BuyStock buyStockOrder = new BuyStock(abcStock);SellStock sellStockOrder = new SellStock(abcStock);

Broker broker = new Broker();broker.takeOrder(buyStockOrder);broker.takeOrder(sellStockOrder);

broker.placeOrders();

23 . 6

24 . 1

Provide a way to access the elements of an aggregate objectsequentially without exposing its underlying representation.

ITERATOR

24 . 2

The concerned classes (ex : People) return a subclasse(PeopleIterator) which implements the Iterator interface.

interface Iterator<T> boolean hasNext(); T next(); //first(); // ...

24 . 2

24 . 3

Remember : In Java, List are Iterable<T>.Set are Iterable<T>.Arrays are not even if the foreach is well dened.

ArrayList<String> list = new ArrayList<>();String[] array = new String[1];

list.add("test1")array[0] = "test1"list.add("test2")array[1] = "test2"

for(String s : list) System.out.println(s);for(String s : array) System.out.println(s);

25 . 1

Allow an object to alter its behaviour when its internal statechanges. The object will appear to change its class.

STATE

Example : Screen in a video game

25 . 2

public abstract class State public abstract void switch(TV context);

public class Off extends State @Override public void switch(TV context) context.setState(new On()); public class On extends State @Override public void switch(TV context) context.setState(new Off());

25 . 2

25 . 3

public class TV public State state;

public void setState(State state) this.state = state; public void pressButton() state.switch(this);

Off initialState = new Off();TV tv = new TV(initialState);//presstv.pressButton();//againtv.pressButton();

25 . 3

26 . 1

Dene an object that encapsulates how a set of objectsinteracts. The mediator pattern promotes loose coupling bykeeping objects from referring to each other explicitly, and it

lets you vary their interaction independently.

MEDIATOR

26 . 2

public class Person protected Mediator mediator; public void send(String msg) mediator.send(this, msg); public void notify(String msg) System.out.println(msg);

public class Boss extends Person

26 . 2

26 . 3

public class Mediator private List<Person> people; private Boss boss; // ... public void send(Person from, String msg) if(from instanceof Boss) for(Person p : people) p.notify("Boss says : "+msg); else boss.notify(from +" : "+msg);

26 . 3

27 . 1

Dene a family of algorithms, encapsulate each one, andmake them interchangeable. The strategy pattern lets the

algorithm vary independently from client to client.

STRATEGY

27 . 2

interface Strategy Path shortestPath(Graph graph, Node begin, Node end);

public class Dijkstra implements Strategy @Override public Path shortestPath(Graph graph, Node begin, Node end) //...

public class AStar implements Strategy @Override public Path shortestPath(Graph graph, Node begin, Node end) //...

27 . 2

27 . 3

public class GraphManager private Graph graph; private Strategy strategy;

public GraphManager(Strategy strategy) this.strategy = strategy;

//set strategy

public int executeStrategy(Node begin, Node end) return strategy.shortestPath(this.graph, begin, end);

GraphManager context = new GraphManager(new Dijkstra());context.executeStrategy(begin, end);

context.setStrategy(new AStar());context.executeStrategy(begin, end);

27 . 3

28 . 1

Avoid coupling the sender of a request to its receiver bygiving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the

chain until an object handles it.

CHAIN OF RESPONSIBILITY

28 . 2

public abstract class AbstractLogger public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3;

protected int level;

protected AbstractLogger nextLogger;

public void logMessage(int level, String message) if(this.level <= level) write(message); if(nextLogger !=null) nextLogger.logMessage(level, message);

28 . 2

28 . 3

public class ConsoleLogger extends AbstractLogger

public ConsoleLogger(int level) this.level = level;

@Override protected void write(String message) System.out.println("Standard Console::Logger: " + message);

public class ErrorLogger extends AbstractLogger

public ErrorLogger(int level) this.level = level;

@Override protected void write(String message) System.out.println("Error Console::Logger: " + message);

28 . 3

28 . 4

//creationAbstractLogger loggerChain = new ErrorLogger(AbstractLogger.ERROR);AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

//chainingloggerChain.setNextLogger(fileLogger);fileLogger.setNextLogger(consoleLogger);

loggerChain.logMessage(AbstractLogger.INFO, "This is an information.");

loggerChain.logMessage(AbstractLogger.DEBUG, "This is an debug level information.");

loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information.");

28 . 4

29 . 1

Represent an operation to be performed on the elements ofan object structure. The visitor pattern lets you dene a new

operation without changing the classes of the elements onwhich it operates.

VISITOR

29 . 2

interface Visitable void accept(Visitor visitor);

public class Book implements Visitable private double price; private double weight; public double getPrice() return price; public double getWeight() return weight;

//accept the visitor @Override public void accept(Visitor vistor) visitor.visit(this);

29 . 2

29 . 3

interface Visitor void visit(Visitable visitable);

public class PostageVisitor implements Visitor private double totalPostageForCart;

public double getTotalPostage() return totalPostageForCart;

//collect data about the book @Override public void visit(Visitable visitable) if(Visitable instanceof Book) //assume we have a calculation here related to weight and price //free postage for a book over 10 if(book.getPrice() < 10.0) totalPostageForCart += book.getWeight() * 2; // else ... other visitables

29 . 3

29 . 4

public class ShoppingCart //normal shopping cart stuff private ArrayList<Visitable> items; public double calculatePostage() //create a visitor PostageVisitor visitor = new PostageVisitor(); //iterate through all items for(Visitable item: items) item.accept(visitor); double postage = visitor.getTotalPostage(); return postage;

29 . 4

30 . 1

Given a language, dene a representation for its grammaralong with an interpreter that uses the representation to

interpret sentences in the language.

INTERPRETER

Example : SQL parsing

30 . 2

interface Expression boolean interpret(String context);

public class TerminalExpression implements Expression private String data;

public TerminalExpression(String data) this.data = data;

@Override public boolean interpret(String context) if(context.contains(data)) return true; return false;

30 . 2

30 . 3

public class OrExpression implements Expression private Expression expr1 = null; private Expression expr2 = null;

public OrExpression(Expression expr1, Expression expr2) this.expr1 = expr1; this.expr2 = expr2;

@Override public boolean interpret(String context) return expr1.interpret(context) || expr2.interpret(context);

public class AndExpression implements Expression private Expression expr1 = null; private Expression expr2 = null;

public AndExpression(Expression expr1, Expression expr2) this.expr1 = expr1; this.expr2 = expr2;

@Override public boolean interpret(String context) return expr1.interpret(context) && expr2.interpret(context);

30 . 3

30 . 4

public class InterpreterPatternDemo

//Rule: Robert and John are male public static Expression getMaleExpression() Expression robert = new TerminalExpression("Robert"); Expression john = new TerminalExpression("John"); return new OrExpression(robert, john);

//Rule: Julie is a married women public static Expression getMarriedWomanExpression() Expression julie = new TerminalExpression("Julie"); Expression married = new TerminalExpression("Married"); return new AndExpression(julie, married);

public static void main(String[] args) Expression isMale = getMaleExpression();

30 . 4

31 . 1

Without violating encapsulation, capture and externalize anobject's internal state so that the object can be restored to

this state later.

MEMENTO

31 . 2

public class Memento<T> private T state;

public Memento(T state) this.state = state;

public T getState() return state;

31 . 2

31 . 3

public class Originator //all internal states // ...

public Memento<Originator> saveToMemento() //...

public void restoreFromMemento(Memento<Originator> memento) //...

public class CareTaker private List<Memento<Originator>> mementoList = new ArrayList<>();

public void add(Memento<Originator> state) mementoList.add(state);

public Memento<Originator> get(int index) return mementoList.get(index);

31 . 3

31 . 4

Originator originator = new Originator();CareTaker careTaker = new CareTaker(); // originator changes;careTaker.add(originator.saveToMemento());// originator changes;careTaker.add(originator.saveToMemento());// originator changes;originator.restoreFromMemento(careTaker.get(0));

31 . 4

32

ARCHITECTURAL PATTERNSData Access ObjectMVCMultitierMicroservicesMessage-driven architecture...

33

@TheGeekTortoise