Post on 22-Jan-2018
transcript
Alonso Torres @alotor
Design Patterns
“ ”
Cada patrón describe un problema recurrente en nuestro entorno, así como la solución a ese problema, de tal modo que se pueda aplicar esta solución un millón de veces, sin hacer lo mismo dos veces.
- Christopher Alexander, A Pattern Language
Los patrones definen:
soluciones a problemas frecuentes
¿ ?
Son las soluciones con Java 8 las mismas que con versiones anteriores
λ
Alonso Torres@alotor
mobro.co/alotor
El camino hacia
1996
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
1994
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
1998 - J2SE 1.2
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
Adopción masiva del
lenguaje
2004 - J2SE 5.0
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
GenéricosAnotacionesEnumeradosNueva sintaxisConcurrencia
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
2011 - Java SE 7
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
InvokeDynamicNIO 2Nueva concurrencia
2014 - Java SE 8
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
Java 8
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
Java 8
● Lambda expressions● Functional interfaces
● Default methods
● Streams
Las lambdas son lo mejor que le ha pasado a Java desde….
Las lambdas son lo mejor que le ha pasado a Java.
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
C#
1990 1995 2000 2005 2010 2015
1.0 1.2 1.4 5 6 7 81.3
ActionScript Groovy Perl
C# Haskell PHP
C++ JavaScript Python
Clojure Lisp R
Curl Logtalk Racket
D Lua Ruby
Dart Mathematica Scala
Dylan Maple Scheme
Erlang Matlab Smalltalk
Elixir Maxima Standard ML
F# OCaml TypeScript
Go Object Pascal Tcl
Gosu Objective-C VisualBasic .NET
Fortran
C
Ada
Cobol
Fortran 1957
C 1969
Ada 1977
Cobol 1989
15%
20%
Features
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
Lambdas: funciones anónimas
public Integer addition(Integer x, Integer y) {
return x + y;
}
public void sayHello(String name) {
System.out.println("Hello " + name);
}
public Float giveMePi() {
return 3.15f;
}
public Integer addition(Integer x, Integer y) {
return x + y;
}
public void sayHello(String name) {
System.out.println("Hello " + name);
}
public Float giveMePi() {
return 3.15f;
}
(Integer x, Integer y) -> {
return x + y;
};
(String name) -> {
System.out.println("Hello" + name);
};
() -> {
return 3.15f;
};
(Integer x, Integer y) -> x + y;
(String name) -> {
System.out.println("Hello" + name);
};
() -> 3.15f
(Integer x, Integer y) -> x + y;
(String name) -> {
System.out.println("Hello" + name);
};
() -> 3.15f
PARÁMETROS CUERPO
(parameters) -> body;
(Integer x, Integer y) -> x + y;
(String name) -> System.out.println("Hello" + name);
() -> 3.15f
Thread th = new Thread(new Runnable(){
@Override
public void run() {
System.out.println(">> Another thread"));
}
});
th.start();
Creando hilos
Thread th = new Thread(() ->
System.out.println(">> Another thread"));
th.start();
Creando hilos
Me váis a llamar loco pero…
…en ocasiones veo patrones
Thread th = new Thread(() ->
System.out.println(">> Another thread"));
th.start();
Creando hilos
Client Invoker
Receiver
+action()
ConcreteCommand
+execute()
Command
+execute()
CommandPATRÓN
new Invoker().addCommand(new Command() {
@Override
public void execute() {
receiver.action();
}
});
new Transaction().doWithTransaction(new Command() {
@Override
public void execute() {
myBusinessLogic.calculateInterests();
}
});
new Context().doAsync(new Command() {
@Override
public void execute() {
networkManager.downloadFile();
}
});
Client Invoker
Receiver
+action()
ConcreteCommand
+execute()
Command
+execute()
Client Invoker
Receiver
+action()
ConcreteCommand
+execute()
Command
+execute()
Lambda
new Invoker().addCommand(new Command() {
@Override
public void execute() {
receiver.action();
}
});
new Invoker().addCommand(new Command() {
@Override
public void execute() {
receiver.action();
}
});
new Invoker().addCommand(
() -> receiver.action();
);
surely,we
can do
better
new Invoker().addCommand(
receiver::action
);
Method Reference
Method Reference:Transformar un método en una lambda
() -> receiver.action()
(el) -> el.toString()
() -> Runtime.getInstance()
() -> new Receiver()
() -> receiver.action()
(el) -> el.toString()
() -> Runtime.getInstance()
() -> new Receiver()
() -> receiver.action() receiver::action
(el) -> el.toString() Object::toString
() -> Runtime.getInstance() Runtime::getInstance
() -> new Receiver() Reciver::new
Instance method reference
(objeto concreto)
Instance method reference
(cualquier objeto)
Static method reference
Constructor reference
receiver::action
Object::toString
Runtime::getInstance
Reciver::new
(Integer x, Integer y) ->
receiver.action(x, y)
(Integer x, Integer y) ->
Math.max(x, y)
(String str) ->
new String(str)
(Integer x, Integer y) ->
receiver.action(x, y)receiver::action
(Integer x, Integer y) ->
Math.max(x, y)
Math::max
(String str) ->
new String(str)String::new
new Transaction().doWithTransaction(
myBusinessLogic::calculateInterests
);
new ThreadPool().doInThread(
networkManager::downloadFile
);
new Transaction().doWithTransaction(
networkManager::downloadFile
);
new ThreadPool().doInThread(
myBusinessLogic::calculateInterests
);
Client Invoker
Receiver
+action()
ConcreteCommand
+execute()
Command
+execute()
Client Invoker
Receiver
+action()
ConcreteCommand
+execute()
Command
+execute()
Client Invoker
Receiver
+action()
Command
+execute()
(Integer x, Integer y) -> x + y;
(String name) -> System.out.println("Hello" + name);
() -> 3.15f
¿Qué TIPO tienen las lambdas?
Object addition =
(Integer x, Integer y) -> x + y;
Object sayHello =
(String name) -> System.out.println("Hello" + name);
Object giveMePi =
() -> 3.15f
¿Qué TIPO tienen las lambdas?
The target type of this expression must be a
functional interface
Java 8
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
(Integer x, Integer y) -> x + y;
(String name) -> System.out.println("Hello" + name);
() -> 3.15f
(Integer x, Integer y) -> x + y;
(String name) -> System.out.println("Hello" + name);
() -> 3.15f
Integer addition(Integer x, Integer y)
void sayHello(String name)
Float giveMePi()
Functional interfaces
public interface Addition {
Integer addition(Integer x, Integer y);
}
public interface SayHello {
void sayHello(String name);
}
public interface GiveMePi {
Float giveMePi();
}
Functional interfaces
public interface Addition {
public Integer addition(Integer x, Integer y);
}
1 sólo método
Functional interfaces
public interface Addition {
public Integer addition(Integer x, Integer y);
}
Addition addition =
(Integer x, Integer y) -> x + y;
public interface Addition {
public Integer addition(Integer x, Integer y);
}
public interface Operation<T extends Number> {
public T do(T x, T y);
}
Operation<Integer> addition =
(Integer x, Integer y) -> x + y;
PROBLEMA
Sólo funciona con interfaces
● NO pueden ser clases
● NI clases abstractas
Java 8
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
Default Methods
public interface Addition {
public Integer addition(Integer x, Integer y);
default Integer substraction(Integer x, Integer y) {
return addition(x, -y);
}
}
public interface Addition {
public Integer addition(Integer x, Integer y);
}
Addition addition =
(Integer x, Integer y) -> x + y;
Si tenemos que definir una “Functional Interface” por cada lambda...
¿Qué hemos ganado?
Java 8 viene con las interfaces más comunes
DE SERIE
import java.util.function.*
BiConsumer<T,U> IntBinaryOperator LongUnaryOperator
BiFunction<T,U,R> IntConsumer ObjDoubleConsumer<T>
BinaryOperator<T> IntFunction<R> ObjIntConsumer<T>
BiPredicate<T,U> IntPredicate ObjLongConsumer<T>
BooleanSupplier IntSupplier Predicate<T>
Consumer<T> IntToDoubleFunction Supplier<T>
DoubleBinaryOperator IntToLongFunction ToDoubleBiFunction<T,U>
DoubleConsumer IntUnaryOperator ToDoubleFunction<T>
DoubleFunction<R> LongBinaryOperator ToIntBiFunction<T,U>
DoublePredicate LongConsumer ToIntFunction<T>
DoubleSupplier LongFunction<R> ToLongBiFunction<T,U>
DoubleToIntFunction LongPredicate ToLongFunction<T>
DoubleToLongFunction LongSupplier UnaryOperator<T>
DoubleUnaryOperator LongToDoubleFunction
Function<T,R> LongToIntFunction
(Integer x, Integer y) -> x + y;
(String name) -> System.out.println("Hello" + name);
() -> 3.15f
¿Qué TIPO tienen?
public Integer addition(Integer x, Integer y)
public void sayHello(String name)
public Float giveMePi()
BiConsumer<T,U> IntBinaryOperator LongUnaryOperator
BiFunction<T,U,R> IntConsumer ObjDoubleConsumer<T>
BinaryOperator<T> IntFunction<R> ObjIntConsumer<T>
BiPredicate<T,U> IntPredicate ObjLongConsumer<T>
BooleanSupplier IntSupplier Predicate<T>
Consumer<T> IntToDoubleFunction Supplier<T>
DoubleBinaryOperator IntToLongFunction ToDoubleBiFunction<T,U>
DoubleConsumer IntUnaryOperator ToDoubleFunction<T>
DoubleFunction<R> LongBinaryOperator ToIntBiFunction<T,U>
DoublePredicate LongConsumer ToIntFunction<T>
DoubleSupplier LongFunction<R> ToLongBiFunction<T,U>
DoubleToIntFunction LongPredicate ToLongFunction<T>
DoubleToLongFunction LongSupplier UnaryOperator<T>
DoubleUnaryOperator LongToDoubleFunction
Function<T,R> LongToIntFunction
import java.util.function.*
BinaryOperator<Integer> addition =
(Integer x, Integer y) -> x + y;
Consumer<String> sayHi =
(String name) -> System.out.println("Hello" + name);
Supplier<Float> giveMePi =
() -> 3.15f
BinaryOperator<Integer> addition =
(x, y) -> x + y;
Consumer<String> sayHi =
(name) -> System.out.println("Hello" + name);
Supplier<Float> giveMePi =
() -> 3.15f
Thread th = new Thread(() ->
System.out.println(">> Another thread"));
th.start();
java.lang.Runnable
JButton button = new JButton("Button");
button.addActionListener((event) ->
System.out.println("Mouse: " + event);
);
java.awt.ActionListener
ObserverPATRÓN
ConcreteObserverA
+notify()
ConcreteObserverB
+notify()
Observer
+notify()
ObservedClass
+registerObserver()+unregisterObserver()+notifyObservers()
Functional Interface
Lambdas!
@FunctionalInterface
public static interface Observer {
public void notify(Object change);
}
@FunctionalInterface
public static interface Observer {
public void notify(Object change);
}
@FunctionalInterface
public static interface Observer {
public void notify(Object change);
}
El compilador fallará si no cumple con las condiciones de una FI.
@FunctionalInterface
public static interface Observer {
public void notify(Object change);
}
El compilador fallará si no cumple con las condiciones de una FI.
Tu yo del futuro te lo agradecerá
public static class ObservedClass {
private List<Observer> observers = new LinkedList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyChange(Object change) {
observers.forEach((o) -> o.notify(change));
}
}
public static class ObservedClass {
private List<Observer> observers = new LinkedList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyChange(Object change) {
observers.forEach((o) -> o.notify(change));
}
}
Una estructura de datos que guarda lambdas.
public static class ObservedClass {
private List<Observer> observers = new LinkedList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyChange(Object change) {
observers.forEach((o) -> o.notify(change));
}
}
Nuevo método de Java 8
observed.addObserver((change) -> {
new Thread(UIThread::update).start()
});
sbj.notifyChange("Change");
Hipótesis
¿Puede haber un patrón de más alto nivel?
new Invoker().addCommand(receiver::action);
observed.addObserver(receiver::action);
Pasar comportamiento como argumentos
● El comportamiento se ejecutará en otro contexto
● “Separation of concerns”
● También conocido como: High Order Functions
new Invoker().addCommand(receiver::action);
observed.addObserver(receiver::action);
List<Person> personList = new LinkedList<>();
Collections.sort(
personList,
(p1, p2) -> p1.age - p2.age
);
java.lang.Comparable<T>
List<Person> personList = new LinkedList<>();
Collections.sort(
personList,
(p1, p2) -> p1.age - p2.age
);
java.lang.Comparable<T>
DATOS
COMPORTAMIENTO
StrategyPATRÓN
Collections.sort( list, (p1, p2) -> p1.getAge() - p2.getAge());
Collections.sort( list, (p1, p2) -> p1.getName().compareTo(p2.getName()));
Collections.sort( list, (p1, p2) -> -p1.getName().compareTo(p2.getName()));
Reusing lambdas
class PersonSortCriterias {
public static int sortByAge(Person p1, Person p2) {
return p1.getAge() - p2.getName();
}
public static int sortByName(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
public static int sortByNameReverse(Person p1, Person p2) {
return -p1.getName().compareTo(p2.getName());
}
}
Collections.sort( list, PersonSortCriterias::sortByAge);
Collections.sort( list, PersonSortCriterias::sortByName);
Collections.sort( list, PersonSortCriterias::sortByNameReverse);
Set<Person> = new TreeSet<>( PersonSortCriterias::sortByAge);
Person theOlder = Collections.max( list, PersonSortCriterias::sortByAge);
list.sort(PersonSortCriterias::sortByAge);
Java 8
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
Java 8
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
IteratorPATRÓN
for (String str : list) {
System.out.println(str);
}
for (String str : list) {
if (str.length <= 5) {
System.out.println(str);
}
}
for (String str : Collections.sort(list)) {
if (str.length <= 5) {
System.out.println(str);
}
}
for (String str : Collections.sort(list).sublist(0, 10)) {
if (str.length <= 5) {
System.out.println(str);
}
}
for (String str : Collections.sort(list).sublist(0, 10)) {
if (str.length <= 5) {
System.out.println(str.toUpperCase());
}
}
Problemas
● Susceptible a errores
● Difícil de razonar
● Difícil de reutilizar
Streams
● Interfaz fluida
● Evaluación perezosa
● Iterable
● Aprovechan toda la expresividad de las lambdas
list.stream()
.forEach(System.out::println);
list.stream()
.filter(s -> s.length <= 5)
.forEach(System.out::println);
list.stream()
.filter(s -> s.length <= 5)
.sorted()
.forEach(System.out::println);
list.stream()
.filter(s -> s.length <= 5)
.sorted()
.limit(10)
.forEach(System.out::println);
list.parallelStream()
.filter(s -> s.length <= 5)
.sorted()
.limit(10)
.forEach(System.out::println);
Funciones importantes
● Map
● Filter
● Reduce
MAP - FILTER - REDUCE
list.stream()
.map(String::toUpperCase)
"banana"
"apple"
"pear"
"pineapple"
"lemon"
"mango"
"raspberry"
"melon"
"BANANA"
"APPLE"
"PEAR"
"PINEAPPLE"
"LEMON"
"MANGO"
"RASPBERRY"
"MELON"
MAP - FILTER - REDUCE
list.stream()
.filter(s -> s.length <= 5)
"banana"
"apple"
"pear"
"pineapple"
"lemon"
"mango"
"raspberry"
"melon"
"apple"
"pear"
"lemon"
"mango"
"melon"
MAP - FILTER - REDUCE
list.stream()
.reduce("", (acc, elem) -> acc + ", " + elem);
"banana"
"apple"
"pear"
"pineapple"
"lemon"
"mango"
"raspberry"
"melon"
"banana,apple,pear,pineapple,...
Chain of responsibility
PATRÓN
HANDLER HANDLER HANDLER HANDLER HANDLERrequest
HANDLER HANDLER HANDLER HANDLER HANDLERrequest
HANDLER HANDLER HANDLER HANDLER HANDLERrequest
HANDLER HANDLER HANDLER HANDLER HANDLERrequest
@FunctionalInterfacepublic interface Handler { public Request handleRequest(Request req);}
@FunctionalInterfacepublic interface Handler extends Function<Request, Request> {}
List<Handler> chain = new LinkedList<>();
chain.add(Request::session);
chain.add(Request::securityCheck);
chain.add(Request::cookies);
chain.add(Request::getParameters);
List<Handler> chain = new LinkedList<>();
chain.add(Request::session);
chain.add(Request::securityCheck);
chain.add(Request::cookies);
chain.add(Request::getParameters);
Request req = new Request();
Request processed = chain.stream() .reduce(initial value, accumulation function)
List<Handler> chain = new LinkedList<>();
chain.add(Request::session);
chain.add(Request::securityCheck);
chain.add(Request::cookies);
chain.add(Request::getParameters);
Request req = new Request();
Request processed = chain.stream() .reduce(req, accumulation function)
List<Handler> chain = new LinkedList<>();
chain.add(Request::session);
chain.add(Request::securityCheck);
chain.add(Request::cookies);
chain.add(Request::getParameters);
Request req = new Request();
Request processed = chain.stream() .reduce(req, (old, handler) -> handler.apply(old))
HANDLER HANDLER HANDLER HANDLER HANDLERrequest
HANDLER HANDLER HANDLER HANDLER HANDLERrequest
CHAIN (HANDLER)
List<Handler> filters = new LinkedList<>();
filters.add(Request::session);
filters.add(Request::securityCheck);
filters.add(Request::cookies);
filters.add(Request::getParameters);
Handler filterChain =
filters.stream()
.reduce(
initial value,
accumulation function);
List<Handler> filters = new LinkedList<>();
filters.add(Request::session);
filters.add(Request::securityCheck);
filters.add(Request::cookies);
filters.add(Request::getParameters);
Handler filterChain =
filters.stream()
.reduce(
(r) -> r,
accumulation function);
List<Handler> filters = new LinkedList<>();
filters.add(Request::session);
filters.add(Request::securityCheck);
filters.add(Request::cookies);
filters.add(Request::getParameters);
Handler filterChain =
filters.stream()
.reduce(
(r) -> r,
(f1, f2) -> f1.andThen(f2));
List<Handler> filters = new LinkedList<>();
filters.add(Request::session);
filters.add(Request::securityCheck);
filters.add(Request::cookies);
filters.add(Request::getParameters);
Handler filterChain =
filters.stream()
.reduce(
Function.identity(),
Function::andThen);
System.out.println("\nProcessing request 1");
Request r1 = chain.apply(new Request());
System.out.println("\nProcessing request 2");
Request r2 = chain.apply(new Request());
Processing request 1>> process session>> process securityCheck>> process cookies>> process getParameters
Processing request 2>> process session>> process securityCheck>> process cookies>> process getParameters
¯\_(ツ)_/¯
Java SE 8
● Lambda expressions
● Functional interfaces
● Default methods
● Streams
Patrones
● Command
● Strategy
● Observer
● Iterator
● Chain of responsibility
Los patrones definen:
soluciones a problemas frecuentes
Problema
● El comportamiento y el contexto son diferentes
● Encapsular los datos
● Composición de comportamiento
Solución
● High order functions (Lambdas)
Las lambdas son lo mejor que le ha pasado a Java.
Sobre los hombros de gigantes
Mario Fusco Venkat Subramaniam Samir Talwarhttps://youtu.be/K6BmGBzIqW0 https://vimeo.com/122645679https://youtu.be/8qcHPEyLkPE
@alotor
mobro.co/alotor
¿Preguntas?
@alotor
Referencias
● https://en.wikipedia.org/wiki/Java_version_history
● http://www.studytrails.com/java/java8/Java8_Lambdas_FunctionalProgramming.jsp
● https://blog.idrsolutions.com/2015/02/java-8-method-references-explained-5-minutes/
● http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
● http://www.javaworld.com/article/2078675/core-java/design-patterns--the-big-picture--part-2--gang-
of-four-classics-revisited.html
● http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns-in-javas-core-libraries
● https://www.questers.com/sites/all/themes/questers/sec_presentation/java8lambdas.html
● http://www.slideshare.net/jaxlondon2012/lambda-a-peek-under-the-hood-brian-goetz
● http://www.infoq.com/presentations/lambda-invokedynamic?
utm_source=infoq&utm_medium=videos_homepage&utm_campaign=videos_row1
● http://www.slideshare.net/DaewonJeong/scala-is-java8next
● http://programmers.stackexchange.com/questions/173441/what-triggered-the-popularity-of-lambda-
functions-in-modern-mainstream-programmi
● http://www.infoq.com/presentations/A-Brief-History-of-the-Java-World
Referencias
● http://j2objc.org/blog/2015/08/07/lambdas-in-java-8-dysfunctional-interfaces.html
● http://gafter.blogspot.com.es/2006/08/closures-for-java.html
● http://www.javaworld.com/article/2077569/core-java/java-tip-68--learn-how-to-implement-the-
command-pattern-in-java.html
● http://www.slideshare.net/mariofusco/fp-in-java-project-lambda-and-beyond?qid=11ae9463-c2e3-
4c54-842f-b228ce109200&v=default&b=&from_search=12
● http://www.norvig.com/design-patterns/design-patterns.pdf
● http://www.techempower.com/blog/2013/03/26/everything-about-java-8/
● http://www.oracle.com/technetwork/server-storage/ts-4961-159222.pdf
● http://talks.samirtalwar.com/design-patterns-in-the-21st-century.html