1 of 130

(OO) Design Patterns

What they’re all about

2 of 130

Examinable Skills from 210

  • 210 completion means ability to…
    • Spot a situation in which we would use composite
    • Spot a situation in which we would use observer
    • Implement each of these patterns according to their design

Composite: https://www.youtube.com/watch?v=THiP0qJlSNk

Observer (without Java's help): https://www.youtube.com/watch?v=s72vPpx2LNA

Observer (with Java's help): https://youtu.be/wEorv69GRfg <<< DEPRACATED!

3 of 130

What is a design pattern?

  • Think about what it feels like to solve a problem for the very first time...
  • You need to think about the problem from scratch
  • You have to test very thoroughly, and maybe won’t even think of all possible cases to test!

A tried and true solution, to a commonly encountered problem

  • Now think about what it’s like when someone tells you a possible solution
  • That solution includes a lot of knowledge, experimentation, and testing!
  • This saves a *lot* of time!!!

4 of 130

Industry noticed this too!

  • Industry noticed this “on your own” versus “with help” phenomenon too.
  • A community developed where people could describe their solutions to commonly encountered problems, and others could benefit
  • They called these solutions “Design Patterns”

Basically, smart people, who have done this a lot, are making a suggestion!

5 of 130

Where does the name come from?

  • The original use of the term “Design Patterns” really comes from Architecture (building architecture) from Christopher Alexander
  • These were architectural idioms, to guide architectural design (a house is composed of a kitchen, bathroom, bedrooms etc... to be placed in certain basic configurations)

6 of 130

Design Patterns Format

  • Alexander provided a nice way to describe these patterns:
          • PROBLEM (whats wrong?)
          • CONTEXT (what’s happening around the problem)
          • SOLUTION (what to do)
  • A Good Dinner Party Every Day Design Pattern
    • PROBLEM: You want your guests to have fun and be impressed by your prowess as a host, chef and sommelier.
    • SOLUTION (abridged):
      • 1. invite people who will like each other. Or, if you want a more lively party, people who will not like each other.
      • 2. greet your guests and introduce them to everyone who is already there.
      • 3. serve dinner, then dessert, then drinks, avoiding allergies of your guests.
    • WARNINGS: might lead to grogginess the next morning. Do not apply this pattern the night before the use of the “Write an Exam” pattern.

7 of 130

This technique was translated into OO S/W Dev

  • Software engineers adopted a similar approach for describing common solutions to common problems
        • PROBLEM: intent, motivation, applicability
        • SOLUTION: structure, participants, collaborations, implementation
        • CONSEQUENCES: warnings, known uses, related patterns

8 of 130

In 310 we’ll focus on OO patterns

OO Design patterns specifically help developers navigate object oriented solutions, and often make smart use of polymorphism to solve some problems.

There are actually lots of kind of software design patterns (Architectural patterns, Web design patterns, etc) but we’re sticking with OO ones in 310.

9 of 130

There are LOTS of OO design patterns!

this is just some of them!

10 of 130

structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities

creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.

behavioural design patterns are design patterns that identify common communication patterns between objects and realize these patterns

They fit into 3 basic categories

Don’t worry about this

11 of 130

CODE SMELLS VIOLATING PRINCIPLES

REFACTORINGS

PRINCIPLED CODE and often PATTERNS

Hence:

Patterns (just like generally principled code) ARISE and EMERGE

We will be looking at each pattern in the context of which principles are violated, which refactorings solve the violations, and how this results naturally in design pattern designs

12 of 130

Emerging to Design Patterns

  • Design patterns provide solutions to commonly encountered problems.
  • OO Design Patterns provide OO solutions to commonly encountered OO problems: These problems manifest as violations of software principles in the code!
  • Usually, OO Design Patterns make use of two important OO foundational technologies:
          • abstraction (creating a more generic superclass)
          • polymorphism (using dynamic substitution to make for more reusable/oblivious code that is more resistant to change)

13 of 130

Basic recipe for understanding a design pattern solution

  1. What principle violations motivate the emergence of the design pattern solution?
  2. Find the abstraction (which class or classes are added at the top of the hierarchy)
  3. Find the polymorphism/obliviousness (which method is present in that class, and how must it be overridden in the subclasses?)
  4. Figure out when the polymorphic method(s) is/are called (what is the trigger for the behaviour in the pattern)

14 of 130

THE OBSERVER PATTERN EMERGENT STORY

Watcher

Watchee

15 of 130

THE OBSERVER PATTERN EMERGENT STORY

WatcherA

Watchee

WatcherB

Lots of notification code

Lots of watching code

Switch on watcher

duplication

Don’t Repeat Yourself!

Single responsibility violation

Dependency Inversion Violation

16 of 130

THE OBSERVER PATTERN EMERGENT STORY

WatcherA

Watchee

WatcherB

Lots of notification code

Lots of watching code

Switch on watcher

duplication

Don’t Repeat Yourself!

Single responsibility violation

extract class

Subject

pull up methods

introduce hierarchy

notify( )

Dependency Inversion Violation

17 of 130

THE OBSERVER PATTERN UNFOLDING STORY

Dependency Inversion Violation

WatcherA

Watchee

WatcherB

Lots of watching code

Switch on watcher

duplication

Single responsibility violation

Subject

Observer

extract class

extract class

pull up method

introduce hierarchy

notify( )

Don’t Repeat Yourself!

update( )

18 of 130

THE OBSERVER PATTERN EMERGENT STORY

WatcherA

Watchee

WatcherB

Subject

Observer

depend on abstraction

Dependency Inversion Violation

notify( )

update( )

*

19 of 130

For Observer...

  • What principles were violated and where?
    1. Duplicated code → SRP → Extract class (once on Obs. and once on Subj)
    2. Switch on type → Depend on concretion → Dependency inversion → Introduce hierarchy and refactor switch to hierarchy.
  • Find the abstraction (which class or classes are added at the top of the hierarchy)
    • Subject and Observer
  • Find the polymorphism/obliviousness (which method is present in that class, and how must it be overridden in the subclasses?)
    • update( )
  • Figure out when the polymorphic method(s) is/are called (what is the trigger)
    • Something in the subject has changed → self.notify → obs.update

20 of 130

Composite - review

“I want to be able to have a hierarchical organisation, but don’t want to write special code for containers and leaf nodes when walking the tree”

The “write special code” is the hint at where the OO polymorphic power play comes in.

21 of 130

Composite — So what is it we don’t want?

for (Leaf leaf : leaves){

leaf.print();

}

for (Group subgroup : subgroups){

subgroup.print();

}

Group.print():

two calls to what should be essentially the same thing

this is going to get annoying if you’re walking the list for lots of reasons!

this is a code smell!

22 of 130

Composite — OO Design pattern solution

Leaf extends component and implements the “operation”

Composite (or Group, or whatever) also extends the Component, implements the “operation”, but also has group-related stuff

We introduce a higher level of abstraction: a “Component”

in our example, the “operation” was print.

void Composite.print:

for (Component c : components){

c.print();

}

isn’t that so much nicer?

void Leaf.print :

print(contents)

23 of 130

For Composite...

  • What code smell → principles are being violated?
    • Duplicated code across all those for loops that are all basically doing the same thing
    • Switch on type special behaviour for groups versus individuals.
    • Switch on type tells us that we have DIP violation.
  • What’s the fix?
    • Introduce Hierarchy.
  • Find the abstraction (which class or classes are added at the top of the hierarchy)
    • Component
  • Find the polymorphism/obliviousness (which method is present in that class, and how must it be overridden in the subclasses?)
    • operation()
  • Figure out when the polymorphic method(s) is/are called (where’s the trigger?)
    • Any time anyone wants to walk the tree

24 of 130

Let’s spot principles violations

Download the starter code here

This is 210 review, but we’re now looking at this from a principles perspective

Activity Link:

https://ubc.ca1.qualtrics.com/jfe/form/SV_cutIgtzIBsASHsx

25 of 130

Examinable Skills So Far

  • 310 examinable skills: the ability to…
    • Identify which SOLID principles are violated, and which code/code smells are responsible for the violation
    • Refactor to Composite fixing the violations
    • Refactor to Observer fixing the violations
    • Explain how polymorphism and abstraction are used in Composite and Observer, includes understanding the concept of obliviousness.

PATTERNS

OBSERVER

COMPOSITE

26 of 130

Now a few more patterns!

Let’s go over a few more examples of OO design patterns, once again examining them wrt

principles, abstraction and polymorphism

27 of 130

Lots of design patterns

28 of 130

We will focus on…

29 of 130

Factory Pattern

  • 1) Construction of your object is a little complicated, or for some reason involves behaviour outside the scope of the responsibility of the class itself — so just putting the behaviour into the constructors isn’t effective.

  • 2) You are not sure what kind of object you want to create at any particular time

INTENT:

A framework needs to standardize the architectural model for a range of applications, but allow for individual applications to define their own domain objects and provide for their instantiation.

http://sourcemaking.com/design_patterns/factory_method

30 of 130

Simplest scenario (not the end of the story)

One single kind of product

This is the real car behaviour

31 of 130

Simplest scenario (not the end of the story)

One single kind of product

This is the real car behaviour

But all of this is about making the car!

So what’s the code smell?

What’s the principle violation?

What’s the fix?

32 of 130

Simplest scenario (not the end of the story)

So this is nice!

No issues.

But the code won’t stay this way.

Note the new routing:

33 of 130

What if we have different kinds of cars?

So what’s the code smell?

What’s the principle violation?

What’s the fix?

34 of 130

Move Car Specific stuff into the factory too!

Making methods move in too

35 of 130

So now we can make different kinds of cars …. But ...

So what’s the code smell?

What’s the principle violation?

What’s the fix?

36 of 130

Introduce a Factory Hierarchy

public static void main(String[] args) {

//Car car = new Car();

//CarFactory carFactory = new CarFactory();

//Car car = carFactory.requestCar("Big");

CarFactory carFactory = new BigCarFactory();

Car car = carFactory.requestCar();

}

37 of 130

Looking at it in context...

public class BigCarFactory extends CarFactory {

@Override

public Car requestCar() {

WheelSet wheels = new BigWheels();

Chassis chassis = new BigChassis();

//and lots more things

return new BigCar(wheels, chassis);

}

}

Same method

public static void main(String[] args) {

//Car car = new Car();

//CarFactory carFactory = new CarFactory();

//Car car = carFactory.requestCar("Big");

CarFactory carFactory = new BigCarFactory();

Car car = carFactory.requestCar();

}

38 of 130

Factory Pattern solution for fixing Creational Overabundance

The official pattern design

39 of 130

Sequence Diagram

Client

ConcreteProductFactory

ConcreteProduct

new

makeProduct()

new

product

product

Passing in all the guts of the work that we just did

40 of 130

Factory analysis

  1. Find the principles violation:

Type Switch → Single Responsibility Violation because of too much construction code AND ALSO constructing two different things!!

  • Find the abstraction (which class or classes are added at the top of the hierarchy)

The factory at the top of the factory hierarchy

AND maybe the product at the top of the product hierarchy

  • Find the polymorphism (which method is present in that class, and how must it be overridden in the subclasses?)

Make the thing makeCar() (in the example it was requestCar() createProduct()

  • Figure out when the polymorphic method(s) is/are called

From the client, Instead of calling the car constructor

41 of 130

But … BUILDER???

I think this is decorator

director

Pizza Makerer

Place base

Place Cheese

Now give it to me

MealBuilder mb;

orderMeal:

mb.addHamburger()

mb.addCheeseburger()

mb.addDrink()

return mb.getMeal()

https://refactoring.guru/design-patterns/builder

42 of 130

Tie In!!!!

Data parser, takes a string, encapsulates in an object

43 of 130

Factory and Principles

Single Responsibility Principle?

Open/Closed Principle?

Liskov Substitution Principle?

Interface Segregation Principle?

Dependency Inversion Principle?

public class BigCarFactory extends CarFactory {

@Override

public Car requestCar() {

WheelSet wheels = new BigWheels();

Chassis chassis = new BigChassis();

//and lots more things

return new BigCar(wheels, chassis);

}

}

public static void main(String[] args) {

CarFactory carFactory = getWhateverKindOfFactoryShopperWants();

carFactory.requestCar();

}

44 of 130

Refactor to Factory!

Take a look at the following code: Player Factory

Right now creation happens right inside of each kind of Player. Imagine it expanding to much more functionality.

Refactor this code into the Factory Pattern.

Determine what the Factory class(es) will be, and what code will be moved out of the original classes.

You try first, and then help me do it!

(Bakery/Cakery solution) (PlayerFactory Solutions)

45 of 130

46 of 130

Examinable Skills for Factory

Identify the principles violations that necessitate the factory pattern (single responsibility principle violation because of excessive construction code)

Identify how to form a Factory class or Factory class hierarchy to capture the construction

Be able to re-route construction through the Factory class(es) in the client (the UI, main, etc)

Refactor a class or class hierarchy where construction has bloated into the Factory pattern.

PATTERNS

FACTORY

47 of 130

Adapter Pattern

Convert the interface of a class into another interface clients expect.

Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Wrap an existing class with a new interface.

http://sourcemaking.com/design_patterns/adapter

don’t want to rewire our plug…

also still don’t want to get electrocuted

it’s a temporary fix, but if we ever went to a different country, we’d have a broken plug!!!

we are in a hotel, so not really allowed to rewire this

also what if we do it wrong??

oh no…

This is a different philosophy!

48 of 130

Adapter Pattern

An "off the shelf" component offers compelling functionality that you would like to reuse, but its "view of the world" is not compatible with the philosophy and architecture of the system currently being developed.

http://sourcemaking.com/design_patterns/adapter

Now I just need one of these for every country I visit, and I don’t risk electrocution!

oh that’s helpful!

Wrong kind of adapter! This is a universal adapter, which will have a switch on type!

No: What you’re describing is the right design.

49 of 130

Simple example

Your code uses a new version of the rectangle, but you still need to be able to use the old version

A special adapter implementation for each adaptee

Adapter

50 of 130

Adapter Pattern

Field name

51 of 130

Adapter Pattern

Field name

displayRoads()

displaySurfaces()

One class doing the work of two --->

SRP violation

52 of 130

MyImplClass

------

displayMap()

displayRoads()

displaySurfaces()

GoogleMapsAPI

-----

Jpeg getMap

JPeg getRoads

Jpeg getSurfaces

MapAdapter

------

PNG getMap()

PNG getRoads

PNG getSurfaces

53 of 130

MyImplClass

------

displayMap()

displayRoads()

displaySurfaces()

GoogleMapsAPI

-----

Jpeg getMap

JPeg getRoads

Jpeg getSurfaces

MapAdapter

------

PNG getMap()

PNG getRoads

PNG getSurfaces

BingMapsAPI

-----

gif getMap

pdf getRoads

Jpeg getSurfaces

54 of 130

MyImplClass

------

displayMap()

displayRoads()

displaySurfaces()

GoogleMapsAPI

-----

Jpeg getMap

JPeg getRoads

Jpeg getSurfaces

GoogleMapAdapter

------

PNG getMap()

PNG getRoads

PNG getSurfaces

BingMapsAPI

-----

gif getMap

pdf getRoads

Jpeg getSurfaces

MapAdapterInterface

------

PNG getMap()

PNG getRoads

PNG getSurfaces

BingMapAdapter

------

PNG getMap()

PNG getRoads

PNG getSurfaces

55 of 130

Adapter Pattern

This is the equivalent of rewiring our plug. Potentially hazardous to our health, and what if we change countries?

bingMaps.getQuad...

56 of 130

Adapter Pattern

Code smell plus violation of SRP

57 of 130

We could make a single adapter

And we are depending on an implementation! Dependency Inversion violated

Switch on Type

58 of 130

So we refactor, and voila, the adapter pattern!

A special adapter implementation for each adaptee

GoogleMapsAdapter

bingMapsServ.getQuad...

59 of 130

So we refactor, and voila, the adapter pattern!

Client

Adapter Interface

Adapter Implementation

Adaptee

AdapterInterface

60 of 130

Interestingly, sometimes this is presented without the abstract class/interface

This is fine, as long as you know you’re not going to want to switch adapters. If you are (and we assume we will) then an adapter interface sets you up better.

Don’t do this on our exam!

61 of 130

So let’s make a plug and socket combo!!

Client

Adapter Interface

Adapter Implementation

Adaptee

Adapter Implementation

Adaptee

62 of 130

Sequence Diagram

Client

Adapter

Adaptee

63 of 130

Let’s analyse

Where is the principle violation? SRP (presence of and likely duplication of conversion code), DIP (switch).

Where is the abstraction? Abstract Adapter (the interface)

Where is the concretization? Concrete Adapter

What is the overridden method (or methods)? ALL of the methods called by originally the client on the adaptee (wall socket).

When is/are the overridden method(s) called?

64 of 130

And what about principles?

Which principle(s) does this pattern most address?

Single Responsibility Principle, DIP

If you do the whole pattern, you get Dependency Inversion.

65 of 130

Examinable Skills for Adapter

Identify when a class has too much conversion code

Identify how to form an Adapter interface and associated implementation (we will always do it in this pairing, even though in practice you may choose to ditch the interface)

Be able to route calls to a desired service through the adapter you have created

Refactor a class or class hierarchy where conversion has bloated into the Adapter pattern.

Explain how the Adapter Pattern ensures principled design as mapped to the SOLID principles

PATTERNS

ADAPTER

66 of 130

A good example from sourcemaking

In this example, all the adaptation is being done in the client -- what principles do we see being violated?

67 of 130

And the solution is…..

Notice: They couldn’t change either Line or Rectangle -- those had to stay exactly the same.

They could, however, change their code to point at the adapter (hierarchy) instead of at the objects themselves

68 of 130

Extra Practice:

Note: The client, the RHAdapterInterface and RHAdapterImplementation (or whatever you want to call them) are the ONLY pieces of the design that should need to change! The whole point of this pattern is that you don't change the client, and you don't change the adaptee (the round hole) other than making certain changes:

- replace the declaration and instantiation with a declaration of the AdapterInterface, and the AdapterImplementation respectively

- rip all the conversion code out of the client, and put it into the AdapterImplementation

- make sure the AdapterInterface (and hence implementation) have one method for each method used by the client.

69 of 130

SP->RH Final Design

Client

Adapter Interface

Adapter Implementation

Adaptee

Main

SquareToSomethingInterface

SquareToRoundAdapter

RoundHole

SquarePeg

constructor-->constructor

putIn-->putIn

putIn-->putIn

70 of 130

Singleton

  • You need to create a class to manage preferences. In order to maintain consistency, there should only ever be one instance of this class.

  • How can you ensure that only one instance of a class is instantiated?

  • (Question: How could your preferences become inconsistent if your class was instantiated more than once?)

71 of 130

Difference static v objects

Class Dog extends Animal

---------

Static maxAge

- Dog ( )

bark( )

Class Dog extends Animal

---------

- static Dog instance

---------

+ static Dog getInstance( )

- Dog ( )

+ breathe( )

+ bark( )

Instance d:@80

@30

Class Animal

---------

breathe( )

@10

Main:

Dog d = new Dog()

Dog d = Dog.getInstance( )

d.bark( );

72 of 130

Singleton

  • You need to create a class to manage preferences. In order to maintain consistency, there should only ever be one instance of this class.

  • How can you ensure that only one instance of a class is instantiated?

  • (Question: How could your preferences become inconsistent if your class was instantiated more than once?)

In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system

Encapsulated "just-in-time initialization" or "initialization on first use".

http://sourcemaking.com/design_patterns/singleton

73 of 130

Singleton … at the code level

class Electorate: % this is the Client

private field President onlyInstance

private method whoIsThePresident():

President thePresident = President.instance()

this means it has an instance of itself

static

74 of 130

Access to a shared resource

Authors contributing to a shared document

public static void main(String[] args) {

Author sal = new Author();

sal.write("It was the best of times");

sal.readAloud();

Author biff = new Author();

biff.write("It was the worst of times");

biff.readAloud();

}

Get the code: CPSC310-Singleton.zip (don’t peek at the solution part)

Main:

Document d = new Doc()

Author sal = new Author(d)� Author bif = new Author(d)

Class Author():

Document d = new Document()

Document d = Document.getInstance();

75 of 130

We don’t want each author to have their own document

Because then we have two documents created!

That’s not collaborative!

But for the sake of argument, let’s say we don’t want to just pass in the document … imagine these authors are created too “distantly” to one another to share an invocation environment.

public static void main(String[] args) {

Author sal = new Author();

sal.write("It was the best of times");

sal.readAloud();

Author biff = new Author();

biff.write("It was the worst of times");

biff.readAloud();

}

76 of 130

So we make a Singleton!

Statically save an instance of the class

Statically provide access to that instance

(creating one if needed)

Protect the constructor, so only the singleton class can call it

LAZY INSTANTIATION

77 of 130

And now the document is collaborative

public static void main(String[] args) {

Author sal = new Author();

sal.write("It was the best of times");

sal.readAloud();

Author biff = new Author();

biff.write("It was the worst of times");

biff.readAloud();

}

2 lines!

78 of 130

Singleton - analysis

  • No abstraction!
  • Singleton breaks this OO meta-pattern convention, perhaps because Singleton is an OO way of making a non OO thing!

WHERE IS THE ABSTRACTION?

WHERE IS THE POLYMORPHISM?

  • Again Singleton breaks the convention
  • there is NO polymorphism here. Instead OO is flipped around to force an object to behave one way.
  • That said, there is a specific “entry point” to the Singleton, similar to how there’s an “entry point” to the typical patterns (the overridden method that allows the polymorphic call).

79 of 130

Singleton - analysis

  • Code smell: Static cling (if you’ve used the static instead of an instance)
  • Single responsibility because otherwise you would have scattered access control code. (lots of “is this instantiated yet?” checks)

WHAT VIOLATION IS IT SOLVING?

WHAT VIOLATION IS IT CAUSING???

  • Dependency inversion (client tied to singleton directly; singleton tied to itself directly!)
  • Single responsibility because of a mix of access control and core behaviour
  • Open closed principle because it has a private constructor!!!

80 of 130

Singletons are going out of style

Because of their technical and design issues�

Because dependency injection is proving to be a better approach since it decouples the access control and the object implementation.

81 of 130

So what’s dependency injection?

Move the construction OUT OF the Author (why is the author making the document anyway?) and into the context.

Pass the document into the Author as an argument as construction time.

Good video on dependency injection WRT testing (old, but still relevant)

https://www.youtube.com/watch?v=acjvKJiOvXw

82 of 130

Examinable Skills for Singleton

Identify when to use the Singleton pattern

Identify an example of when it is being used by looking for its main features (protected constructor by making it private, static instance field)

Be able to apply the Singleton pattern to an existing class, or create one from scratch

Explain how to access the Singleton instance by calling getInstance instead of calling the constructor

Explain how singleton relates to design principles (good and bad)

Explain the difference between Singleton and Dependency Injection

PATTERNS

SINGLETON

83 of 130

State

State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.

CS310-State.zip (barista and person projects)

84 of 130

The Moody Barista

85 of 130

The Moody Barista

public class Barista {

private int annoyingDelay;

private String mood;

private int customerNumber=0;

public void makeCoffee() throws InterruptedException {

setMood();

getBeans();

expressCoffee();

giveCustomerCoffee();

goodbye();

}

private void goodbye() throws InterruptedException {

if (mood =="Chatty") System.out.println("Have a lovely day!!!!");

if (mood =="Curt") System.out.println("bye.");

Thread.sleep(annoyingDelay);

}

private void giveCustomerCoffee() throws InterruptedException {

if (mood =="Chatty") System.out.println("Hope this is to your liking!");

if (mood =="Curt") System.out.println("Here.");

Thread.sleep(annoyingDelay);

}

This if-statement is everywhere … our instinct is to refactor the switch to different types of Barrista … but let’s look deeper...!

86 of 130

The Moody Barista

setMood is called every single time the Barrista makes coffee!

We can’t get a whole new barista object every time the barista changes moods. We need to be able to maintain a pointer to the same object, so that it can maintain its own internal information, but we want the barista to behave differently!

So … refactor to ChattyBarrista, and CurtBarrista

won’t work!

87 of 130

Barista

-------

+makeCoffee

MoodBehaviour

-------

-giveCoffee

-goodbye

private void goodbye() throws InterruptedException {

if (mood =="Chatty") System.out.println("Have a lovely day!!!!");

if (mood =="Curt") System.out.println("bye.");

Thread.sleep(annoyingDelay);

}

private void giveCustomerCoffee() throws InterruptedException {

if (mood =="Chatty") System.out.println("Hope this is to your liking!");

if (mood =="Curt") System.out.println("Here.");

Thread.sleep(annoyingDelay);

}

88 of 130

Barista

-------

+makeCoffee

MoodBehaviour

-------

-giveCoffee

-goodbye

CurtBehaviour

-------

-giveCoffee

-goodbye

ChattyBehaviour

-------

-giveCoffee

-goodbye

public void makeCoffee(){

setMood();

mood.giveCoffee();

mood.goodbye();

}

public void setMood(){

If thingsaregoingbadly(){

mood = new CurtBehaviour() }

else

mood = new ChattyBehaviour()

}

mood

89 of 130

The Moody Barrista

Yes, our refactor to types is mostly right: we still need a mood hierarchy (we still have different kinds of behaviours, and they still have things in common that we need to abstract)

<<should be dashed lines>>

90 of 130

The Moody Barista

But we want the Barista to HAVE those mood behaviours, not BE those moods. So the right answer is …..

Delegation!

91 of 130

And voila the State Pattern

<<interface>>

92 of 130

The total Moody Barista

Notice the delegation to moodstrat for every behaviour!

getBeans

getBeans

mood.getBeans()

This is a field!!!!!!!

Alternate way of doing it if there are no changes to makeCoffee() -- every method delegates to the Mood instance

93 of 130

State Analysis

How does State satisfy or exemplify each of the SOLID principles?

What abstraction is introduced?

What concretisation is introduced?

What method(s) is/are overridden?

Where are those methods called?

From within the context of use, through delegation

State class (whatever you called it).

Subtypes of the state class (like happy/sad/grumpy or “waiting” or some implementation class that extends State)

Any methods defined in the State class that require the affected behaviour

“handle” or some bunch of operations

Which principles was it trying to solve:

Smell is type switch ---> single responsibility principle because class is trying to embody multiple states at once.

94 of 130

State Machines

with the State Pattern

95 of 130

State and Strategy

The Strategy pattern is identical to state except that the client is choosing a single strategy and sticking with it.

It’s like if the Barista never changed moods -- just got initialised with one mood at the beginning of their career and stayed the same forever.

96 of 130

State Examinable Skills

Be able to explain why delegation is a better option than subclassing the Client class

Be able to explain the abstraction, concretisation, and polymorphism involved, as well as how and when the overridden method is invoked.

Be able to relate the State pattern to code smells and design principles.

Be able to explain and implement the simple version of the pattern and the state machine version of the pattern

Be able to explain how it relates to Strategy

PATTERNS

STATE

STRATEGY

97 of 130

Visitor Pattern

98 of 130

Examinable Skills

  • Identify when a visitor pattern is needed
  • Identify which parts of a codebase that does not use a visitor should be refactored into a visitor and perform the refactoring
  • Be able to construct a visitor from scratch to visit each element in a hierarchy
  • Be able to add Visitable and accept() to your language nodes to allow a 3rd party visitor to visit!
  • Be able to explain the back and forth pattern in visitor is needed (because of Java’s single dispatch mechanism)

99 of 130

Let’s look at a basic implementation of a Row Selector

Client

Get the code

MiniRowSelector

Starter code from the refactoring lecture: https://github.students.cs.ubc.ca/CPSC310/toy-project-refactoring

100 of 130

Each query becomes a tree (called an Abstract Syntax Tree)

Selection

Not

Selection

Has

“Red”

101 of 130

Each query becomes a tree (called an Abstract Syntax Tree)

Selection

And

Selection

Has

“Red”

Selection

Has

“Green”

102 of 130

And during parsing, every node calls “parse” on each of its subnodes

Selection

And

Selection

Has

“Red”

Selection

Has

“Green”

parse

parse

parse

parse

parse

parse

parse

Each parse method does two things:

  1. it instantiates and stores the subnode(s) (forming the tree)
  2. calls parse on the subnode(s).

103 of 130

And during evaluating, every node calls “evaluate” on each of its subnodes

Selection

And

Selection

Has

“Red”

Selection

Has

“Green”

evaluate

evaluate

evaluate

evaluate

evaluate

evaluate

evaluate

Each evaluate method returns a value for the node, sometimes calling evaluate on the subnodes if needed

104 of 130

So where does “Parsing” live? Everywhere!

Client

Parsing

SCATTERED CONCERN!

105 of 130

And where does “evaluation” live? Everywhere!

Client

Evaluation

SCATTERED CONCERN!

106 of 130

And what about each individual class? Are those designs sound?

Client

TANGLING: SRP violation!

Divergent changes!

CODE SMELL:

One class doing the work of two

107 of 130

So what would you want

Node

Selection

And

Not

Client

Parser

Evaluator

Has

108 of 130

So what would you want

Node

Selection

And

Not

Client

Parser

Evaluator

parse Selection

parse And

parse Not

parse Has

evaluate Selection

evaluate And

evaluate Not

evaluate Has

Has

109 of 130

But there’s an implementation problem!

Parser

parse Selection

parse And

parse Not

parse Has

Selection

And

Selection

Has

Selection

Has

If we’re moving all the parsing to the Parser class, we need calls to be within the Parser class!

parse

parse

parse

parse

parse

How, if we are in parse Selection, will we know which other parse method to call?

But the pointer to the child node lives in the AST and not in the Parser

110 of 130

So we move all the parse methods into the Parser

Let’s start with the parser…..

111 of 130

We make the references external

Yes, there is feature envy. This is a tradeoff.

112 of 130

And then we need to fix the call down to selection!

So why isn’t that line of code compiling?

Because selection in “node.selection” is declared as a Node.

We don’t have a parse method with “Node” as the argument type.

PARAMETER TYPES ARE DETERMINED AT COMPILATION!

We can try casting in this case….. But ….

113 of 130

So casting works if we know exactly what we will have

We could do a <shudder> switch on type?

But that’s horrible. And it would need to be in every single parse method that can have multiple kinds of children (prone to error!)

114 of 130

So on what can we blame our problem?

But Java binds PARAMETERS at COMPILE TIME

Java binds RECEIVERS at RUNTIME

This is called SINGLE DISPATCH

So we can know the dynamic type (actual type) of the receiver (meaning the object on which the method is called)

But we can only know the DECLARED type (apparent type) of the parameters

115 of 130

So Single Dispatch is our problem

Single Dynamic Dispatch means that only one (single) thing is taken into account when deciding which method to call.

That one single thing is the type of the receiver.

this.got(a)

Public void got(A a){ always calls this one }

116 of 130

What would multiple dispatch look like?

This won’t work, because Java does not support multiple dispatch!

This code won’t compile!!!

117 of 130

So instead we need to use Double Dispatch

118 of 130

DEFINITIONS

SINGLE DISPATCH: The dispatch (method calling) mechanism that Java uses to decide which method to call -- it uses ONE SINGLE dynamic piece of information: The dynamic type of the *RECEIVER* (aka: the object on which the method is called.

DOUBLE DISPATCH: Is a TRICK you can use in a single dispatch language, to gain access to the dynamic type of a parameter passed into a method, without using a switch on INSTANCE OF type.

119 of 130

Parser with DOUBLE DISPATCH

Parser

ParserVisitor’s parse(Selection) method calls selection.subnode.accept(this)

The compiler won’t know what selection.subnode really is.

But the runtime environment will!

Let’s say it’s the “And” node.

accept(this)

Selection

And

Selection

Has

Selection

Has

The “this” variable’s type was bound at compile time. But because it is sitting RIGHT IN the “And” class, it was bound to “And”.

So then when we call p.parse(this), the parse method that gets called will be the one that takes the “And” parameter!

1

2

We introduce a new method accept(Parser p){

p.parse(this)

}

Into every class

parse(this)

120 of 130

And do the same for Evaluate

Evaluator

accept(this)

Selection

And

Selection

Has

Selection

Has

We introduce a new method accept(Evaluator e){

return e.evaluate(this)

}

Into every class

evaluate(this)

121 of 130

But …. duplication!

Evaluator

Now, in every class we’ve got pretty much the same code!

accept(this)

Selection

And

Selection

Has

Selection

Has

evaluate(this)

accept(Parser p){

p.parse(this)

}

accept(Evaluator e){

e.evaluate(this)

}

Parser

accept(this)

parse(this)

122 of 130

So … Abstract!

Evaluator

accept(this)

Selection

And

Selection

Has

Selection

Has

visit(this)

accept(Parser p){

p.parse(this)

}

accept(Evaluator e){

e.evaluate(this)

}

Parser

accept(this)

visit(this)

Visitor

accept(Visitor v){

v.visit(this)

}

Both of these methods can just be one generic “accept” method

123 of 130

Visitor needs a “visit” method for every Node

And all the rest of the visit methods too

124 of 130

And we can easily make new visitors

We could make a tree-walker that prints out each node in the tree as we visit it.

this is a Selection

visitSelection(

125 of 130

So what are the dynamics with the new naming...

visit(Statement node):

node.subnode.accept(this)

visit(And print):

//do And stuff...

accept(Visitor v):

v.visit(this)

And

ParseVisitor

Let’s imagine stmt is a “PRINT”

statically bound

This two call approach for the sake of accessing the dynamic type is called

double dispatch

126 of 130

And we’ve arrived at the canonical visitor!

Put all the visit methods, for all the different types of nodes, in a single ConcreteVisitor

Eclipse’s ASTVisitor has 95 public methods: one for each type of Java language AST node:

...

127 of 130

Examinable Skills for Visitor

  • Identify when a visitor pattern is needed
  • Identify which parts of a codebase that does not use a visitor should be refactored into a visitor and perform the refactoring
  • Be able to construct a visitor from scratch (or through refactoring) to visit each element in a hierarchy
  • Be able to add accept() methods to your hierarchy nodes to allow a 3rd party visitor to visit!
  • Be able to explain the back and forth pattern in visitor is needed (because of Java’s single dispatch mechanism)

128 of 130

Activity

Starting with the with_visitors package of the MiniRowSelector project, extract an EvaluatorVisitor.

(for fun, you can add more language features if you want)

Activity Link: https://ubc.ca1.qualtrics.com/jfe/form/SV_eRmZQCGRHkkoNFk

And your Parser visitor will also have to change its signature:

public class ParserVisitor extends Visitor<Void> {

With methods looking like:

public Void visit(...){

Note: Because the evaluator/interp method returns a value, the declaration for the EvaluatorVisitor class will have to be:

public class EvaluatorVisitor extends Visitor<Boolean> {

And the methods will each have to return a Boolean like this:

public Boolean visit(...

129 of 130

public class Interpreter extends Visitor<Boolean>{

public final String row;

public Interpreter(String row){

this.row=row;

}

@Override

Boolean visit(And node) {

return (node.selection1.accept(this)) &&

(node.selection2.accept(this));

}

130 of 130

(in node) public abstract <X> X accept(Visitor<X> v);

In the nodes themselves:

public <X> X accept(Visitor<X> v){

return v.visit(this);

}