SlideShare a Scribd company logo
1 of 65
Download to read offline
Design Patterns

in the 21st Century
12th February 2015
@SamirTalwar
What do you want
from me?
I want you to stop using design patterns.

What do you want
from me?
I want you to stop using design patterns…

like it’s 1999.
The elements of this language are entities
called patterns. Each pattern describes a
problem that occurs over and over again in our
environment, and then describes the core of the
solution to that problem, in such a way that you
can use this solution a million times over,
without ever doing it the same way twice.
– Christopher Alexander
And now, an aside, on
functional programming.
int courses = 3;
Course dessert =

prepareCake.madeOf(chocolate);
Preparation prepareCake = new Preparation() {

@Override

public Course madeOf(Ingredient mmmmm) {

return

new CakeMix(eggs, butter, sugar)

.combinedWith(mmmmm);

}

};
Preparation prepareCake = new Preparation() {

@Override

public Course madeOf(Ingredient mmmmm) {

return

new CakeMix(eggs, butter, sugar)

.combinedWith(mmmmm);

}

};
@FunctionalInterface

interface Preparation {

Course madeOf(Ingredient mmmmm);

}
Preparation prepareCake = new Preparation() {

@Override

public Course madeOf(Ingredient mmmmm) {

return

new CakeMix(eggs, butter, sugar)

.combinedWith(mmmmm);

}

};
Preparation prepareCake =

mmmmm ->

new CakeMix(eggs, butter, sugar)

.combinedWith(mmmmm);
Preparation prepareCake =

mmmmm ->

new CakeMix(eggs, butter, sugar)

.combinedWith(mmmmm);
Mix mix = new CakeMix(eggs, butter, sugar);

Preparation prepareCake =

mix::combinedWith;
Preparation prepareCake =

mmmmm ->

new CakeMix(eggs, butter, sugar)

.combinedWith(mmmmm);
Mix mix = new CakeMix(eggs, butter, sugar);

Preparation prepareCake =

mix::combinedWith;
Course combinedWith(Ingredient);
@FunctionalInterface

interface Preparation {

Course madeOf(Ingredient mmmmm);

}
Well.
On to the Good Stuff
The

Abstract Factory

pattern
public interface Bakery {

Pastry bakePastry(Topping topping);



Cake bakeCake();

}
public class DanishBakery implements Bakery {

@Override

public Pastry bakePastry(Topping topping) {

return new DanishPastry(topping);

}



@Override

public Cake bakeCake() {

return new Æblekage(); // mmmm, apple cake…

}

}
Abstract Factory
public interface Bakery {

Pastry bakePastry(Topping topping);

}
public class DanishBakery implements Bakery {

@Override

public Pastry bakePastry(Topping topping) {

return new DanishPastry(topping);

}

}
Abstract Factory
public class DanishBakery implements Bakery {

@Override

public Pastry bakePastry(Topping topping) {

return new DanishPastry(topping);

}

}
Bakery danishBakery = topping ->

new DanishPastry(topping);
Bakery danishBakery = DanishPastry::new;
Abstract Factory
package java.util.function;



/**

* Represents a function that

* accepts one argument and produces a result.

*

* @since 1.8

*/

@FunctionalInterface

public interface Function<T, R> {

/**

* Applies this function to the given
argument.

*/

R apply(T t);



...

}
Abstract Factory
public class DanishBakery

implements Function<Topping, Pastry> {

@Override

public Pastry apply(Topping topping) {

return new DanishPastry(topping);

}

}
Function<Topping, Pastry> danishBakery

= topping ->

new DanishPastry(topping);
Function<Topping, Pastry> danishBakery

= DanishPastry::new;
Abstract Factory
The

Adapter

pattern
interface Fire {

<T> Burnt<T> burn(T thing);

}
interface Oven {

Food cook(Food food);

}
class WoodFire implements Fire { ... }
class MakeshiftOven

extends WoodFire

implements Oven {

@Override public Food cook(Food food) {

Burnt<Food> nastyFood = burn(food);

return nastyFood.scrapeOffBurntBits();

}

}
Adapter
interface Fire {

<T> Burnt<T> burn(T thing);

}
interface Oven {

Food cook(Food food);

}
class MakeshiftOven implements Oven {

private final Fire fire;



public MakeshiftOven(Fire fire) { /* ... */ }



@Override public Food cook(Food food) {

Burnt<Food> nastyFood = fire.burn(food);

return nastyFood.scrapeOffBurntBits();

}

}
Adapter
interface Oven {

Food cook(Food food);

}
Oven oven = new MakeshiftOven(fire);

Food bakedPie = oven.cook(pie);
Adapter
interface Oven {

Food cook(Food food);

}
class MakeshiftOven implements Oven {

private final Fire fire;



public MakeshiftOven(Fire fire) { /* ... */ }



@Override public Food cook(Food food) {

Burnt<Food> nastyFood = fire.burn(food);

return nastyFood.scrapeOffBurntBits();

}

}
Adapter
class MakeshiftOven implements Oven {

private final Fire fire;



public MakeshiftOven(Fire fire) { /* ... */ }



@Override public Food cook(Food food) {

Burnt<Food> nastyFood = fire.burn(food);

return nastyFood.scrapeOffBurntBits();

}

}
Oven oven = food -> {

Burnt<Food> nastyFood = fire.burn(food);

return nastyFood.scrapeOffBurntBits();

};

Food bakedPie = oven.cook(pie);
Adapter
Oven oven = food -> {

Burnt<Food> nastyFood = fire.burn(food);

return nastyFood.scrapeOffBurntBits();

};
Oven oven = food ->

fire.burn(food).scrapeOffBurntBits();
Adapter
Oven oven = food ->

fire.burn(food).scrapeOffBurntBits();
// Do *not* do this.

Function<Food, Burnt<Food>> burn

= fire::burn;

Function<Food, Food> cook

= burn.andThen(Burnt::scrapeOffBurntBits);

Oven oven = cook::apply;

Food bakedPie = oven.cook(pie);
Adapter
package java.util.concurrent;



/**

* An object that executes

* submitted {@link Runnable} tasks.

*/

public interface Executor {

void execute(Runnable command);

}
Adapter
public interface Executor {

void execute(Runnable command);

}
Executor executor = ...;

Stream<Runnable> tasks = ...;
tasks.forEach(executor);
Adapter
public interface Stream<T> {

...



void forEach(Consumer<? super T> action);



...

}
@FunctionalInterface

public interface Consumer<T> {

void accept(T t);



...

}
Adapter
public interface Executor {

void execute(Runnable command);

}



@FunctionalInterface

public interface Consumer<T> {

void accept(T t);

}
Executor executor = ...;

Stream<Runnable> tasks = ...;
tasks.forEach(task -> executor.execute(task));
tasks.forEach(executor::execute);
Adapter
executor::execute
Adapter
The

Chain of Responsibility

pattern
@Test public void hungryHungryPatrons() {

KitchenStaff alice = new PieChef();

KitchenStaff bob = new DollopDistributor();

KitchenStaff carol = new CutleryAdder();

KitchenStaff dan = new Server();



alice.setNext(bob);

bob.setNext(carol);

carol.setNext(dan);



Patron patron = new Patron();

alice.prepare(new Pie()).forPatron(patron);



assertThat(patron, hasPie());

}
Chain of
Responsibility
public final class HitCounterFilter implements Filter {

private FilterConfig filterConfig = null;



public void init(FilterConfig filterConfig) throws ServletException {

this.filterConfig = filterConfig;

}



public void destroy() {

this.filterConfig = null;

}



public void doFilter

(ServletRequest request, ServletResponse response, FilterChain chain) 

throws IOException, ServletException {

if (filterConfig == null)

return;



Counter counter =

(Counter)filterConfig.getServletContext().getAttribute("hitCounter");



StringWriter sw = new StringWriter();

PrintWriter writer = new PrintWriter(sw);

writer.println("The number of hits is: " + counter.incCounter());

writer.flush();

filterConfig.getServletContext().log(sw.getBuffer().toString());



chain.doFilter(request, response);

}

}
Chain of
Responsibility
public final class HitCounterFilter

implements Filter {

// init and destroy



public void doFilter(

ServletRequest request,

ServletResponse response,

FilterChain chain) {

int hits = getCounter().incCounter();

log(“The number of hits is ” + hits);

chain.doFilter(request, response);

}

}
Chain of
Responsibility
public final class SwitchEncodingFilter

implements Filter {

// init and destroy



public void doFilter(

ServletRequest request,

ServletResponse response,

FilterChain chain) {



request.setEncoding(“UTF-8”);

chain.doFilter(request, response);

}

}
Chain of
Responsibility
public final class AuthorizationFilter

implements Filter {

// init and destroy



public void doFilter(

ServletRequest request,

ServletResponse response,

FilterChain chain) {

if (!user.canAccess(request))

throw new AuthException(user);

chain.doFilter(request, response);

}

}
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

KitchenStaff alice = new PieChef();

KitchenStaff bob = new DollopDistributor();

KitchenStaff carol = new CutleryAdder();

KitchenStaff dan = new Server();



alice.setNext(bob);

bob.setNext(carol);

carol.setNext(dan);



Patron patron = new Patron();

alice.prepare(new Pie()).forPatron(patron);



assertThat(patron, hasPie());

}
Chain of
Responsibility
Chain of
Responsibility
Ick.
So much mutation.
Where’s the start?
What happens if we change the order?
Why do we duplicate the chain logic in every
element?
@Test public void hungryHungryPatrons() {

KitchenStaff alice = new PieChef();

KitchenStaff bob = new DollopDistributor();

KitchenStaff carol = new CutleryAdder();

KitchenStaff dan = new Server();



alice.setNext(bob);

bob.setNext(carol);

carol.setNext(dan);



Patron patron = new Patron();

alice.prepare(new Pie()).forPatron(patron);



assertThat(patron, hasPie());

}
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

KitchenStaff dan = new Server();

KitchenStaff carol = new CutleryAdder(dan);

KitchenStaff bob = new DollopDistributor(carol);

KitchenStaff alice = new PieChef(bob);



Patron hungryPatron = new HungryPatron();

Patron happyPatron = alice.prepare(new Pie())

.forPatron(hungryPatron);



assertThat(happyPatron, hasPie());

}
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

KitchenStaff<WithCutlery<Meal>> dan

= new Server();

KitchenStaff<Meal> carol

= new CutleryAdder(dan);

KitchenStaff<CookedPie> bob

= new DollopDistributor(carol);

KitchenStaff<UncookedPie> alice

= new PieChef(bob);



Patron hungryPatron = new HungryPatron();

Patron happyPatron = alice.prepare(new Pie())

.forPatron(hungryPatron);



assertThat(happyPatron, hasPie());

}
Chain of
Responsibility
public PieChef(KitchenStaff next) {

this.next = next;

}



public PieChef(KitchenStaff<CookedPie> next) {

this.next = next;

}
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

KitchenStaff<WithCutlery<Meal>, Serving> dan

= new Server();

KitchenStaff<Meal, Serving> carol

= new CutleryAdder().then(dan);

KitchenStaff<CookedPie, Serving> bob

= new DollopDistributor().then(carol);

KitchenStaff<UncookedPie, Serving> alice

= new PieChef().then(bob);



Patron hungryPatron = new HungryPatron();

Patron happyPatron = alice.prepare(new Pie())

.forPatron(hungryPatron);



assertThat(happyPatron, hasPie());

}
Chain of
Responsibility
interface KitchenStaff<I, O> {

O prepare(I input);



default <Next> KitchenStaff<I, Next>

then(KitchenStaff<O, Next> next) {

return input -> {

O output = prepare(input);

return next.prepare(output);

};

}

}
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

KitchenStaff<UncookedPie, CookedPie> alice

= new PieChef();

KitchenStaff<CookedPie, Meal> bob

= new DollopDistributor();

KitchenStaff<Meal, WithCutlery<Meal>> carol

= new CutleryAdder();

KitchenStaff<WithCutlery<Meal>, Serving> dan

= new Server();



KitchenStaff<UncookedPie, Serving> staff =

alice.then(bob).then(carol).then(dan);



Patron hungryPatron = new HungryPatron();

Patron happyPatron = staff.prepare(new Pie())

.forPatron(hungryPatron);



assertThat(happyPatron, hasPie());

}
Chain of
Responsibility
@FunctionalInterface

public interface Function<T, R> {

R apply(T t);



...



default <V> Function<T, V> andThen

(Function<? super R, ? extends V> after) {

Objects.requireNonNull(after);

return (T t) -> after.apply(apply(t));

}



...

}
Chain of
Responsibility
:-O
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

Function<UncookedPie, CookedPie> alice

= new PieChef();

Function<CookedPie, Meal> bob

= new DollopDistributor();

Function<Meal, WithCutlery<Meal>> carol

= new CutleryAdder();

Function<WithCutlery<Meal>, Serving> dan

= new Server();



Function<UncookedPie, Serving> staff =

alice.andThen(bob).andThen(carol).andThen(dan);



Patron hungryPatron = new HungryPatron();

Patron happyPatron = staff.apply(new Pie())

.forPatron(hungryPatron);



assertThat(happyPatron, hasPie());

}
Chain of
Responsibility
@Test public void hungryHungryPatrons() {

Function<UncookedPie, CookedPie> alice = UncookedPie::cook;

Function<CookedPie, Meal> bob = CookedPie::addCream;

Function<Meal, WithCutlery<Meal>> carol = WithCutlery::new;

Function<WithCutlery<Meal>, Serving> dan = Serving::new;



Function<UncookedPie, Serving> staff =

alice.andThen(bob).andThen(carol).andThen(dan);



Patron hungryPatron = new HungryPatron();

Patron happyPatron = staff.prepare(new Pie())

.forPatron(hungryPatron);



assertThat(happyPatron, hasPie());

}
Chain of
Responsibility
So.
So.What’s your point?
I want you to use design patterns…

like it’s 1958.
λ O O P
Credits
Bakery, by Boris Bartels
Just baked, by Sergio Russo
cherry pie with crumble topping, by Ginny
This presentation is licensed under

Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
talks.samirtalwar.com
Thank you.

More Related Content

Similar to Design patterns in the 21st Century

VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
Darwin Durand
 

Similar to Design patterns in the 21st Century (20)

Pragmatic functional refactoring with java 8 (1)
Pragmatic functional refactoring with java 8 (1)Pragmatic functional refactoring with java 8 (1)
Pragmatic functional refactoring with java 8 (1)
 
Android TDD
Android TDDAndroid TDD
Android TDD
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
QA your code: The new Unity Test Framework – Unite Copenhagen 2019
QA your code: The new Unity Test Framework – Unite Copenhagen 2019QA your code: The new Unity Test Framework – Unite Copenhagen 2019
QA your code: The new Unity Test Framework – Unite Copenhagen 2019
 
Solid principles
Solid principlesSolid principles
Solid principles
 
Symfony (Unit, Functional) Testing.
Symfony (Unit, Functional) Testing.Symfony (Unit, Functional) Testing.
Symfony (Unit, Functional) Testing.
 
Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOL
 
Flink Batch Processing and Iterations
Flink Batch Processing and IterationsFlink Batch Processing and Iterations
Flink Batch Processing and Iterations
 
Gwt and Xtend
Gwt and XtendGwt and Xtend
Gwt and Xtend
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design Principles
 
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
 
Be pragmatic, be SOLID
Be pragmatic, be SOLIDBe pragmatic, be SOLID
Be pragmatic, be SOLID
 
Async JavaScript in ES7
Async JavaScript in ES7Async JavaScript in ES7
Async JavaScript in ES7
 
MCE^3 - Gregory Kick - Dagger 2
MCE^3 - Gregory Kick - Dagger 2 MCE^3 - Gregory Kick - Dagger 2
MCE^3 - Gregory Kick - Dagger 2
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
Google guava
Google guavaGoogle guava
Google guava
 

Recently uploaded

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Recently uploaded (20)

The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 

Design patterns in the 21st Century

  • 1. Design Patterns
 in the 21st Century 12th February 2015 @SamirTalwar
  • 2. What do you want from me? I want you to stop using design patterns.

  • 3. What do you want from me? I want you to stop using design patterns…
 like it’s 1999.
  • 4.
  • 5. The elements of this language are entities called patterns. Each pattern describes a problem that occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. – Christopher Alexander
  • 6. And now, an aside, on functional programming.
  • 7. int courses = 3; Course dessert =
 prepareCake.madeOf(chocolate); Preparation prepareCake = new Preparation() {
 @Override
 public Course madeOf(Ingredient mmmmm) {
 return
 new CakeMix(eggs, butter, sugar)
 .combinedWith(mmmmm);
 }
 };
  • 8. Preparation prepareCake = new Preparation() {
 @Override
 public Course madeOf(Ingredient mmmmm) {
 return
 new CakeMix(eggs, butter, sugar)
 .combinedWith(mmmmm);
 }
 }; @FunctionalInterface
 interface Preparation {
 Course madeOf(Ingredient mmmmm);
 }
  • 9. Preparation prepareCake = new Preparation() {
 @Override
 public Course madeOf(Ingredient mmmmm) {
 return
 new CakeMix(eggs, butter, sugar)
 .combinedWith(mmmmm);
 }
 }; Preparation prepareCake =
 mmmmm ->
 new CakeMix(eggs, butter, sugar)
 .combinedWith(mmmmm);
  • 10. Preparation prepareCake =
 mmmmm ->
 new CakeMix(eggs, butter, sugar)
 .combinedWith(mmmmm); Mix mix = new CakeMix(eggs, butter, sugar);
 Preparation prepareCake =
 mix::combinedWith;
  • 11. Preparation prepareCake =
 mmmmm ->
 new CakeMix(eggs, butter, sugar)
 .combinedWith(mmmmm); Mix mix = new CakeMix(eggs, butter, sugar);
 Preparation prepareCake =
 mix::combinedWith; Course combinedWith(Ingredient); @FunctionalInterface
 interface Preparation {
 Course madeOf(Ingredient mmmmm);
 }
  • 12. Well.
  • 13. On to the Good Stuff
  • 15. public interface Bakery {
 Pastry bakePastry(Topping topping);
 
 Cake bakeCake();
 } public class DanishBakery implements Bakery {
 @Override
 public Pastry bakePastry(Topping topping) {
 return new DanishPastry(topping);
 }
 
 @Override
 public Cake bakeCake() {
 return new Æblekage(); // mmmm, apple cake…
 }
 } Abstract Factory
  • 16.
  • 17. public interface Bakery {
 Pastry bakePastry(Topping topping);
 } public class DanishBakery implements Bakery {
 @Override
 public Pastry bakePastry(Topping topping) {
 return new DanishPastry(topping);
 }
 } Abstract Factory
  • 18. public class DanishBakery implements Bakery {
 @Override
 public Pastry bakePastry(Topping topping) {
 return new DanishPastry(topping);
 }
 } Bakery danishBakery = topping ->
 new DanishPastry(topping); Bakery danishBakery = DanishPastry::new; Abstract Factory
  • 19. package java.util.function;
 
 /**
 * Represents a function that
 * accepts one argument and produces a result.
 *
 * @since 1.8
 */
 @FunctionalInterface
 public interface Function<T, R> {
 /**
 * Applies this function to the given argument.
 */
 R apply(T t);
 
 ...
 } Abstract Factory
  • 20. public class DanishBakery
 implements Function<Topping, Pastry> {
 @Override
 public Pastry apply(Topping topping) {
 return new DanishPastry(topping);
 }
 } Function<Topping, Pastry> danishBakery
 = topping ->
 new DanishPastry(topping); Function<Topping, Pastry> danishBakery
 = DanishPastry::new; Abstract Factory
  • 21.
  • 23. interface Fire {
 <T> Burnt<T> burn(T thing);
 } interface Oven {
 Food cook(Food food);
 } class WoodFire implements Fire { ... } class MakeshiftOven
 extends WoodFire
 implements Oven {
 @Override public Food cook(Food food) {
 Burnt<Food> nastyFood = burn(food);
 return nastyFood.scrapeOffBurntBits();
 }
 } Adapter
  • 24. interface Fire {
 <T> Burnt<T> burn(T thing);
 } interface Oven {
 Food cook(Food food);
 } class MakeshiftOven implements Oven {
 private final Fire fire;
 
 public MakeshiftOven(Fire fire) { /* ... */ }
 
 @Override public Food cook(Food food) {
 Burnt<Food> nastyFood = fire.burn(food);
 return nastyFood.scrapeOffBurntBits();
 }
 } Adapter
  • 25. interface Oven {
 Food cook(Food food);
 } Oven oven = new MakeshiftOven(fire);
 Food bakedPie = oven.cook(pie); Adapter
  • 26.
  • 27. interface Oven {
 Food cook(Food food);
 } class MakeshiftOven implements Oven {
 private final Fire fire;
 
 public MakeshiftOven(Fire fire) { /* ... */ }
 
 @Override public Food cook(Food food) {
 Burnt<Food> nastyFood = fire.burn(food);
 return nastyFood.scrapeOffBurntBits();
 }
 } Adapter
  • 28. class MakeshiftOven implements Oven {
 private final Fire fire;
 
 public MakeshiftOven(Fire fire) { /* ... */ }
 
 @Override public Food cook(Food food) {
 Burnt<Food> nastyFood = fire.burn(food);
 return nastyFood.scrapeOffBurntBits();
 }
 } Oven oven = food -> {
 Burnt<Food> nastyFood = fire.burn(food);
 return nastyFood.scrapeOffBurntBits();
 };
 Food bakedPie = oven.cook(pie); Adapter
  • 29. Oven oven = food -> {
 Burnt<Food> nastyFood = fire.burn(food);
 return nastyFood.scrapeOffBurntBits();
 }; Oven oven = food ->
 fire.burn(food).scrapeOffBurntBits(); Adapter
  • 30. Oven oven = food ->
 fire.burn(food).scrapeOffBurntBits(); // Do *not* do this.
 Function<Food, Burnt<Food>> burn
 = fire::burn;
 Function<Food, Food> cook
 = burn.andThen(Burnt::scrapeOffBurntBits);
 Oven oven = cook::apply;
 Food bakedPie = oven.cook(pie); Adapter
  • 31. package java.util.concurrent;
 
 /**
 * An object that executes
 * submitted {@link Runnable} tasks.
 */
 public interface Executor {
 void execute(Runnable command);
 } Adapter
  • 32. public interface Executor {
 void execute(Runnable command);
 } Executor executor = ...;
 Stream<Runnable> tasks = ...; tasks.forEach(executor); Adapter
  • 33. public interface Stream<T> {
 ...
 
 void forEach(Consumer<? super T> action);
 
 ...
 } @FunctionalInterface
 public interface Consumer<T> {
 void accept(T t);
 
 ...
 } Adapter
  • 34. public interface Executor {
 void execute(Runnable command);
 }
 
 @FunctionalInterface
 public interface Consumer<T> {
 void accept(T t);
 } Executor executor = ...;
 Stream<Runnable> tasks = ...; tasks.forEach(task -> executor.execute(task)); tasks.forEach(executor::execute); Adapter
  • 36.
  • 38. @Test public void hungryHungryPatrons() {
 KitchenStaff alice = new PieChef();
 KitchenStaff bob = new DollopDistributor();
 KitchenStaff carol = new CutleryAdder();
 KitchenStaff dan = new Server();
 
 alice.setNext(bob);
 bob.setNext(carol);
 carol.setNext(dan);
 
 Patron patron = new Patron();
 alice.prepare(new Pie()).forPatron(patron);
 
 assertThat(patron, hasPie());
 } Chain of Responsibility
  • 39. public final class HitCounterFilter implements Filter {
 private FilterConfig filterConfig = null;
 
 public void init(FilterConfig filterConfig) throws ServletException {
 this.filterConfig = filterConfig;
 }
 
 public void destroy() {
 this.filterConfig = null;
 }
 
 public void doFilter
 (ServletRequest request, ServletResponse response, FilterChain chain) 
 throws IOException, ServletException {
 if (filterConfig == null)
 return;
 
 Counter counter =
 (Counter)filterConfig.getServletContext().getAttribute("hitCounter");
 
 StringWriter sw = new StringWriter();
 PrintWriter writer = new PrintWriter(sw);
 writer.println("The number of hits is: " + counter.incCounter());
 writer.flush();
 filterConfig.getServletContext().log(sw.getBuffer().toString());
 
 chain.doFilter(request, response);
 }
 } Chain of Responsibility
  • 40. public final class HitCounterFilter
 implements Filter {
 // init and destroy
 
 public void doFilter(
 ServletRequest request,
 ServletResponse response,
 FilterChain chain) {
 int hits = getCounter().incCounter();
 log(“The number of hits is ” + hits);
 chain.doFilter(request, response);
 }
 } Chain of Responsibility
  • 41. public final class SwitchEncodingFilter
 implements Filter {
 // init and destroy
 
 public void doFilter(
 ServletRequest request,
 ServletResponse response,
 FilterChain chain) {
 
 request.setEncoding(“UTF-8”);
 chain.doFilter(request, response);
 }
 } Chain of Responsibility
  • 42. public final class AuthorizationFilter
 implements Filter {
 // init and destroy
 
 public void doFilter(
 ServletRequest request,
 ServletResponse response,
 FilterChain chain) {
 if (!user.canAccess(request))
 throw new AuthException(user);
 chain.doFilter(request, response);
 }
 } Chain of Responsibility
  • 43.
  • 44. @Test public void hungryHungryPatrons() {
 KitchenStaff alice = new PieChef();
 KitchenStaff bob = new DollopDistributor();
 KitchenStaff carol = new CutleryAdder();
 KitchenStaff dan = new Server();
 
 alice.setNext(bob);
 bob.setNext(carol);
 carol.setNext(dan);
 
 Patron patron = new Patron();
 alice.prepare(new Pie()).forPatron(patron);
 
 assertThat(patron, hasPie());
 } Chain of Responsibility
  • 45. Chain of Responsibility Ick. So much mutation. Where’s the start? What happens if we change the order? Why do we duplicate the chain logic in every element?
  • 46. @Test public void hungryHungryPatrons() {
 KitchenStaff alice = new PieChef();
 KitchenStaff bob = new DollopDistributor();
 KitchenStaff carol = new CutleryAdder();
 KitchenStaff dan = new Server();
 
 alice.setNext(bob);
 bob.setNext(carol);
 carol.setNext(dan);
 
 Patron patron = new Patron();
 alice.prepare(new Pie()).forPatron(patron);
 
 assertThat(patron, hasPie());
 } Chain of Responsibility
  • 47. @Test public void hungryHungryPatrons() {
 KitchenStaff dan = new Server();
 KitchenStaff carol = new CutleryAdder(dan);
 KitchenStaff bob = new DollopDistributor(carol);
 KitchenStaff alice = new PieChef(bob);
 
 Patron hungryPatron = new HungryPatron();
 Patron happyPatron = alice.prepare(new Pie())
 .forPatron(hungryPatron);
 
 assertThat(happyPatron, hasPie());
 } Chain of Responsibility
  • 48. @Test public void hungryHungryPatrons() {
 KitchenStaff<WithCutlery<Meal>> dan
 = new Server();
 KitchenStaff<Meal> carol
 = new CutleryAdder(dan);
 KitchenStaff<CookedPie> bob
 = new DollopDistributor(carol);
 KitchenStaff<UncookedPie> alice
 = new PieChef(bob);
 
 Patron hungryPatron = new HungryPatron();
 Patron happyPatron = alice.prepare(new Pie())
 .forPatron(hungryPatron);
 
 assertThat(happyPatron, hasPie());
 } Chain of Responsibility
  • 49. public PieChef(KitchenStaff next) {
 this.next = next;
 }
 
 public PieChef(KitchenStaff<CookedPie> next) {
 this.next = next;
 } Chain of Responsibility
  • 50. @Test public void hungryHungryPatrons() {
 KitchenStaff<WithCutlery<Meal>, Serving> dan
 = new Server();
 KitchenStaff<Meal, Serving> carol
 = new CutleryAdder().then(dan);
 KitchenStaff<CookedPie, Serving> bob
 = new DollopDistributor().then(carol);
 KitchenStaff<UncookedPie, Serving> alice
 = new PieChef().then(bob);
 
 Patron hungryPatron = new HungryPatron();
 Patron happyPatron = alice.prepare(new Pie())
 .forPatron(hungryPatron);
 
 assertThat(happyPatron, hasPie());
 } Chain of Responsibility
  • 51. interface KitchenStaff<I, O> {
 O prepare(I input);
 
 default <Next> KitchenStaff<I, Next>
 then(KitchenStaff<O, Next> next) {
 return input -> {
 O output = prepare(input);
 return next.prepare(output);
 };
 }
 } Chain of Responsibility
  • 52. @Test public void hungryHungryPatrons() {
 KitchenStaff<UncookedPie, CookedPie> alice
 = new PieChef();
 KitchenStaff<CookedPie, Meal> bob
 = new DollopDistributor();
 KitchenStaff<Meal, WithCutlery<Meal>> carol
 = new CutleryAdder();
 KitchenStaff<WithCutlery<Meal>, Serving> dan
 = new Server();
 
 KitchenStaff<UncookedPie, Serving> staff =
 alice.then(bob).then(carol).then(dan);
 
 Patron hungryPatron = new HungryPatron();
 Patron happyPatron = staff.prepare(new Pie())
 .forPatron(hungryPatron);
 
 assertThat(happyPatron, hasPie());
 } Chain of Responsibility
  • 53. @FunctionalInterface
 public interface Function<T, R> {
 R apply(T t);
 
 ...
 
 default <V> Function<T, V> andThen
 (Function<? super R, ? extends V> after) {
 Objects.requireNonNull(after);
 return (T t) -> after.apply(apply(t));
 }
 
 ...
 } Chain of Responsibility
  • 55. @Test public void hungryHungryPatrons() {
 Function<UncookedPie, CookedPie> alice
 = new PieChef();
 Function<CookedPie, Meal> bob
 = new DollopDistributor();
 Function<Meal, WithCutlery<Meal>> carol
 = new CutleryAdder();
 Function<WithCutlery<Meal>, Serving> dan
 = new Server();
 
 Function<UncookedPie, Serving> staff =
 alice.andThen(bob).andThen(carol).andThen(dan);
 
 Patron hungryPatron = new HungryPatron();
 Patron happyPatron = staff.apply(new Pie())
 .forPatron(hungryPatron);
 
 assertThat(happyPatron, hasPie());
 } Chain of Responsibility
  • 56. @Test public void hungryHungryPatrons() {
 Function<UncookedPie, CookedPie> alice = UncookedPie::cook;
 Function<CookedPie, Meal> bob = CookedPie::addCream;
 Function<Meal, WithCutlery<Meal>> carol = WithCutlery::new;
 Function<WithCutlery<Meal>, Serving> dan = Serving::new;
 
 Function<UncookedPie, Serving> staff =
 alice.andThen(bob).andThen(carol).andThen(dan);
 
 Patron hungryPatron = new HungryPatron();
 Patron happyPatron = staff.prepare(new Pie())
 .forPatron(hungryPatron);
 
 assertThat(happyPatron, hasPie());
 } Chain of Responsibility
  • 57.
  • 58. So.
  • 60.
  • 61. I want you to use design patterns…
 like it’s 1958.
  • 62. λ O O P
  • 63. Credits Bakery, by Boris Bartels Just baked, by Sergio Russo cherry pie with crumble topping, by Ginny This presentation is licensed under
 Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 64.