Design Patterns I Technion – Institute of Technology

Slides:



Advertisements
Similar presentations
Observer Method 1. References Gamma Erich, Helm Richard, “Design Patterns: Elements of Reusable Object- Oriented Software” 2.
Advertisements

Object-Oriented Design Patterns Composite Singleton State Observer … Autumn 2012UCN Technology: IT/Computer Science1.
SE2811 Week 7, Class 2 The Gang of Four and more … Lab Thursday: Quiz SE-2811 Slide design: Dr. Mark L. Hornick Content: Dr. Hornick Errors: Dr. Yoder.
DESIGN PATTERNS OZGUR RAHMI DONMEZ.
Design Patterns CS is not simply about programming
Design Patterns. What are design patterns? A general reusable solution to a commonly occurring problem. A description or template for how to solve a problem.
Object-Oriented Analysis and Design
Design Patterns academy.zariba.com 1. Lecture Content 1.What are Design Patterns? 2.Creational 3.Structural 4.Behavioral 5.Architectural 6.Design Patterns.
1 An introduction to design patterns Based on material produced by John Vlissides and Douglas C. Schmidt.
Design Patterns.
CSSE 374: 3½ Gang of Four Design Patterns These slides derived from Steve Chenoweth, Shawn Bohner, Curt Clifton, and others involved in delivering 374.
Design Patterns Part two. Structural Patterns Concerned with how classes and objects are composed to form larger structures Concerned with how classes.
ISP666 MVC & Design Patterns. Outline Review Event Programming Model Model-View-Controller Revisit Simple Calculator Break Design Patterns Exercise.
Patterns in programming 1. What are patterns? “A design pattern is a general, reusable solution to a commonly occurring problem in software. A design.
Dependency Injection Technion – Institute of Technology Author: Gal Lalouche - Technion 2015 ©
Design Patterns CSCI 5801: Software Engineering. Design Patterns.
ECE450 - Software Engineering II1 ECE450 – Software Engineering II Today: Design Patterns IX Interpreter, Mediator, Template Method recap.
Software Design Patterns (1) Introduction. patterns do … & do not … Patterns do... provide common vocabulary provide “shorthand” for effectively communicating.
Object Oriented Software Engineering Chapter 16 and 17 review 2014/06/03.
CSE 403 Lecture 14 Design Patterns. Today’s educational objective Understand the basics of design patterns Be able to distinguish them from design approaches.
Patterns in programming1. 2 What are patterns? Answers to common design problems. A language used by developers –To discuss answers to design problems.
Design Patterns CSIS 3701: Advanced Object Oriented Programming.
Behavioural Design Patterns Quote du jour: ECE450S – Software Engineering II I have not failed. I've just found 10,000 ways that won't work. - Thomas Edison.
OO Methodology Elaboration Iteration 2 - Design Patterns -
DESIGN PATTERNS COMMONLY USED PATTERNS What is a design pattern ? Defining certain rules to tackle a particular kind of problem in software development.
Sadegh Aliakbary. Copyright ©2014 JAVACUP.IRJAVACUP.IR All rights reserved. Redistribution of JAVACUP contents is not prohibited if JAVACUP.
Gang of Four Patterns 23 total 15 useful How are they different from GRASP Patterns?
Dependency Injection Frameworks Technion – Institute of Technology Author: Assaf Israel - Technion 2013 ©
Dependency Injection with Guice Technion – Institute of Technology Author: Gal Lalouche - Technion 2016 ©
CLASSIFICATION OF DESIGN PATTERNS Hladchuk Maksym.
Design Patterns CSCE 315 – Programming Studio Spring 2013.
1 Lecture Material Design Patterns Visitor Client-Server Factory Singleton.
Elaboration: Iteration 2. Elaboration: Iteration 2 Basics Iteration 1 ends with : All the software has been tested: The idea in the UP is to do early,
Patterns in programming
Facade Pattern Jim Fawcett CSE776 – Design Patterns Summer 2010
GRASP – Designing Objects with Responsibilities
Design Patterns: MORE Examples
Design Patterns Technion – Institute of Technology Spring 2016
Design Patterns: Brief Examples
Design Patterns Spring 2017.
The Object-Oriented Thought Process Chapter 15
Design Patterns II Technion – Institute of Technology
Chapter 10 Design Patterns.
GoF Patterns (GoF) popo.
MPCS – Advanced java Programming
Design Patterns Lecture part 2.
Test Isolation and Mocking
Behavioral Design Patterns
Observer Design Pattern
Facade Pattern Jim Fawcett CSE776 – Design Patterns Summer 2010
object oriented Principles of software design
SOEN 343 Software Design Computer Science and Software Engineering Department Concordia University Fall 2005 Instructor: Patrice Chalin.
How to be a Good Developer
Multiuser Protection and the Mediator Pattern
Advanced Programming Behnam Hatami Fall 2017.
Introduction to Design Patterns Part 1
Frameworks And Patterns
Informatics 122 Software Design II
Abstract Class As per dictionary, abstraction is the quality of dealing with ideas rather than events. For example, when you consider the case of ,
Advanced Java Programming
Behavioral Design Pattern
DESIGN PATTERNS : Introduction
SOEN 343 Software Design Computer Science and Software Engineering Department Concordia University Fall 2004 Instructor: Patrice Chalin.
Fundaments of Game Design
Design Patterns Imran Rashid CTO at ManiWeber Technologies.
Informatics 122 Software Design II
Object Oriented Design
Chapter 8, Design Patterns Introduction
Jim Fawcett CSE687 – Object Oriented Design Spring 2014
Presentation transcript:

Design Patterns I Technion – Institute of Technology 236700 Author: Gal Lalouche - Technion 2017 © Technion – Institute of Technology 236700 Spring 2017 Author: Gal Lalouche

Design patterns What are design patterns? Reusable, tested, proven solution templates to common, recurring problems ‘Design Patterns, Elements of Reusable Object-Oriented Software’ by: Gemma, Helm, Johnson, Vlissides A.K.A. Gang of Four, or GoF A common language of software design solutions Author: Gal Lalouche - Technion 2017 ©

Categories Behavioural Creational Structural Describes a process/flow and classes can assign responsibilities between each other Examples taught: Observer, Visitor, Template Creational Revolves around the creation and instantiation of objects Examples taught: Factories, Singleton Structural How classes and objects are composed to form new structures Examples taught: Proxy, Composite Author: Gal Lalouche - Technion 2017 © Factory and abstract Factory were taught in the DI tutorial Template will be taught in the lectures

Observer: Motivation The problem: We are developing an IDE We want to be notified whenever a file changes Example uses: Recompile Updating indexes Update our source control Author: Gal Lalouche - Technion 2017 ©

Observer: Alternatives Invoke all the required functions whenever we modify the file What's the problem? We've increased MyFile's coupling Hard to expand with new behavior (have to modify the class) class MyFile { // this can be invoked in any number of ways… private void onChange() { Compiler.compile(this); indexUpdater.update(this); sourceControl.update(this); } public void write(String s) { // other logic… onChange(); Author: Gal Lalouche - Technion 2017 ©

Observer: Solution Decouple the File (Observable) from those who want to be notified on changes (Observers) Both Observable and Observers can be oblivious to each other Pass a listener callback that will be invoked on changes Depending on the number of parameters, this can be a Runnable, Consumer<T>, BiConsumer<T>, or a new custom interface With a custom interface, we could also listen to multiple event types It also makes more sense (and is more declarative) to implement a custom listenable than a standard library one Author: Gal Lalouche - Technion 2017 © class Compiler implement Runnable … // ??? class Compiler impelement FileChangeListener // ah okay

Observer: Implementation Observable: Observers: interface MyFileObserver { // or use the standard Consumer<MyFile> void notify(MyFile f); } class MyFile { private void Collection<MyFileObserver> observers = new HashSet<>(); public final void listen(MyFileObserver o) { observers.add(o); public final void unlisten(MyFileObserver o) { observers.remove(o); private final void onChange() { observers.forEach(l -> l.notify(this)); Author: Gal Lalouche - Technion 2017 © // we can either use lambdas/method references myFile.listen(compiler::compile) // or implement an interface class IndexUpdater implements MyFileObserver { … } myFile.listen(indexUpdater);

Observer: Advanced implementations Abstract class (simply extend for functionality): Save us from writing boiler plate, but uses our single inheritance slot Why can't we use an interface with default methods? Included in the standard library, but it's for a pre-generic version Best to avoid, use RxJava's version instead abstract class Observable<T> { private void Collection<Consumer<T>> listeners = new HashSet<>(); public final void listen(Consumer<T> c) { listeners.add(o); } public final void unlisten(Consumer<T> c) { listeners.remove(o); protected final void onChange(T t) { listeners.forEach(c -> c.accept(t)); class MyFile extends Observable<MyFile> { public void write(String s) { // … writing logic onChange(this); Author: Gal Lalouche - Technion 2017 ©

Observer: Applicability Use the observer pattern when: You want to decouple event creators from their consumers Both observers and observables are decoupled from each other Observables don't care how the observer is implemented: busy wait, Thread.notify, explicit publishing, … Observers don't care what observables do with the information But they might care how long they take; consider invoking actions on a separate thread to avoid starvations You want to expose an event based API This pattern is very common in GUI programming Listening on button clicks, form changes, etc. A generalization of the observer pattern is the publish-subscriber architecture (AKA pubsub) Publishers publish to a topic, subscribers listen to a topic, a central service mediates the two Author: Gal Lalouche - Technion 2017 ©

Observer: Implications Easy to expand with new behaviors Easy to test with mocks Observers and observables are completely decoupled Includes a fair bit of boilerplate But we can often use libraries to avoid that Is inherently stateful Have to keep a mutable list of its listeners It's possible to get around this, but usually not worth the effort Author: Gal Lalouche - Technion 2017 ©

Proxy: Motivation Problem: We have a remote server that we send packets to When sending each packet, we first have to establish a connection, perform a “handshake” protocol, etc. In other words, there is a lot of overhead for every sent packet In order to minimize the overhead of packet transfer, we would like to buffer all packets, and send them 10 at a time… But putting all of that logic in the client would hurt its cohesion interface Server { void sendPacket(Packet p); } Author: Gal Lalouche - Technion 2017 ©

Proxy: Alternatives Okay, let’s put the buffer logic in a buffer class, and invoke that Problems? We just moved the logic to another class, but the client still has to account for it, and the client is now coupled with the Buffer class What if we want to replace the buffer logic with a retry logic? What if we want to compose logics (both buffer and retry)? class Buffer { void add(Packet p) { … } int size() { … } // aggregates all packets together, and deletes them from memory Packet getMegaPacketAndClear() { … } } buffer.add(new MessagePacket(…)); buffer.add(new BytePacket(…)); buffer.add(new NumberPacket(…)); if (buffer.size() >= 10) server.send(buffer.getMegaPacketAndClear()); Author: Gal Lalouche - Technion 2017 ©

Proxy: Solution Wrap the server with a buffer, but expose the same interface Client code is unchanged If we tested using mocks, our unit tests are unchanged as well! Easy to compose behavior: simply pass Proxy X to Proxy Y Proxies are oblivious to proxies too! class ServerBuffer implements Server { private final Server s; private final Buffer buffer = new BufferImpl(); public ServerBuffer(Server s) { this.s = s; } @Override void sendPacket(Packet p) { buffer.add(p); if (buffer.size() >= 10) server.send(buffer.getMegaPacketAndClear()); } Author: Gal Lalouche - Technion 2017 © Server retryBufferServer = new RetryServer(new BufferServer(server));

Proxy: Applicability Use the Proxy pattern when You want to wrap an existing implementation You want to hide the refinement from the client You want to enable linear composition of behaviors Other types of proxies include: RetryProxy CacheProxy RemoteProxy ProtectiveProxy Author: Gal Lalouche - Technion 2017 ©

Proxy: Implications Client is oblivious to the change (True) unit tests don't need to be modified Can compose proxies The extra layer of abstraction may surprise the client For example, the client may be surprised when the messages are buffered rather than sent immediately (Integration) tests may fail Author: Gal Lalouche - Technion 2017 ©

Composite: Motivation Problem: We want to implement logging in our application There are several ways in which we can log messages Write the message to the console Write it a file Write it in a database Send it to a remote server We usually want to log to more than one service interface Logger { void log(String s); } // specific implementation class ConsoleLogger implements Logger { @Override void log(String s) { System.out.println(s); } class FileLogger implements Logger { … } class RemoteLogger implements Logger { … } Author: Gal Lalouche - Technion 2017 ©

Composite: Alternatives I Okay, so we'll pass around an Iterable<Logger> instead of Logger Problems? Annoying to use & test Very verbose We have to modify all our current logging clients // old client code class MyClass { private final Logger logger; public MyClass(Logger logger) { this.logger = logger; } public void myMethod() { logger.log("My method called"); } // new client code private final Iterable<Logger> loggers; public MyClass(Iterable<Logger> loggers) { this.loggers = loggers; } loggers.forEach(l -> l.log("My method called")); Author: Gal Lalouche - Technion 2017 ©

Composite: Alternatives II I know, this is a proxy pattern! Yes, but not quite While proxy pattern does solve this, it's a very verbose solution // this times how many logger we have class ConsoleProxyLogger implements Logger { private final Logger logger; public ProxyLogger(Logger logger) { this.logger = logger; } public void log(String s) { System.out.println(s); logger.log(s); // logger creation new ConsoleLoggerProxy( new FileLoggerProxy(fileLogger, new SqlLoggerProxy(…))); Author: Gal Lalouche - Technion 2017 ©

Composite: Solution The composite pattern is actually a special case of a proxy that accepts several elements: Defining a composite logger is now very easy: Logging clients code is unchanged class CompositeLogger implements Logger { private final Iterable<Logger> loggers; public CompositeLogger(Iterable<Logger> loggers) { this.loggers = loggers; } @Override public void log(String s) { loggers.forEach(s -> log()); Author: Gal Lalouche - Technion 2017 © Logger compLogger = new CompositeLogger(Arrays.asList(consoleLogger, fileLogger, sqlLogger, …);

Composite: Applicability Use composites when you want to treat multiple elements as a single elements Of course, composites can be composed of other composites Popular examples include: compound expressions – literals or an operation on expression UI widgets – a UI widget can be composed of multiple, children widgets, e.g., a form contains multiple text boxes and button, and possibly sub forms Guice Modules – using the Modules.combine method Composites compositions form a directed tree Proxy compositions form a linear list Author: Gal Lalouche - Technion 2017 ©

Composite: Implications Clients is (again) oblivious to the change Can compose multiple composites recursively The (potentially exponential) added number of operations may surprise clients Deep compositions can be very hard to keep track off and reason about e.g., Guice modules It's much easier to follow a list (Proxy) than a tree Author: Gal Lalouche - Technion 2017 ©