Post on 25-Jan-2015
description
DEVCON 2013
Anti- Object Oriented Design Patterns
Alvaro Polo
DEVCON 2013
Design Patterns
What’s a design pattern?
“A general reusable solu-on to a commonly occurring problem within a given context in so8ware design”, Wikipedia
DEVCON 2013
Design Patterns
But, what kind of commonly ocurring problem are we talking about?
DEVCON 2013
Design Patterns
No, this is all about software design
DEVCON 2013
Problems unsolved by the language
_uppercase: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp movq %rdi, -8(%rbp) movl %esi, -12(%rbp) movl $0, -16(%rbp)
LBB0_1: movl -16(%rbp), %eax cmpl -12(%rbp), %eax jge LBB0_3 movslq -16(%rbp), %rax movq -8(%rbp), %rcx movb (%rcx,%rax), %dl movb %dl, -17(%rbp) movsbl -17(%rbp), %esi cmpl $97, %esi jl LBB0_2
movsbl -17(%rbp), %eax cmpl $122, %eax jg LBB0_2 movsbl -17(%rbp), %eax addl $65, %eax subl $97, %eax movb %al, %cl movslq -16(%rbp), %rdx movq -8(%rbp), %rsi movb %cl, (%rsi,%rdx)
LBB0_2: movl -16(%rbp), %eax addl $1, %eax movl %eax, -16(%rbp) jmp LBB0_1
LBB0_3: popq %rbp ret
DEVCON 2013
Problems unsolved by the language
_uppercase: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp movq %rdi, -8(%rbp) movl %esi, -12(%rbp) movl $0, -16(%rbp)
begin_for: movl -16(%rbp), %eax cmpl -12(%rbp), %eax jge end_for movslq -16(%rbp), %rax movq -8(%rbp), %rcx movb (%rcx,%rax), %dl movb %dl, -17(%rbp) movsbl -17(%rbp), %esi cmpl $97, %esi jl end_if
movsbl -17(%rbp), %eax cmpl $122, %eax jg end_if movsbl -17(%rbp), %eax addl $65, %eax subl $97, %eax movb %al, %cl movslq -16(%rbp), %rdx movq -8(%rbp), %rsi movb %cl, (%rsi,%rdx)
end_if: movl -16(%rbp), %eax addl $1, %eax movl %eax, -16(%rbp) jmp begin_for
end_for: popq %rbp ret
void uppercase(char *str, int strl) { for (int i = 0; i < strl; i++) { char c = str[i]; if (c >= 'a' && c <= 'z') str[i] = 'A' + c - 'a'; } }
DEVCON 2013
Problems caused by the language
We want to represent IPv4 addresses in our Java program. Suggestions? class IpV4Address {
private uint bits = 0; public static IpV4Address fromCidr(String cidr) { ... } public bool isInSameNetwork(IpV4Address addr, Netmask netmask) { ... } ... };
DEVCON 2013
Problems caused by the language
We want to represent IPv4 addresses in our program. Suggestions? class IpV4Address {
private uint bits = 0; public static IpV4Address fromCidr(String cidr) { ... } public bool isInSameNetwork(IpV4Address addr, Netmask netmask) { ... } ... };
DEVCON 2013
Problems caused by the language
Let me introduce the An@-‐ Object Oriented Design PaGerns
DEVCON 2013
Singleton Pattern
DEVCON 2013
Singleton Pattern
public class Application extends Configurable { private static Application instance; private Application() { ... } public static Application getInstance() { if (instance == null) instance = new Application(); return instance; } // The functionality of the application goes here ... }
OOP establishes some constraints: ü Every object is bounded to a lifecycle ü Every class has as many instances as fit into
memory
Singleton is fighting against these rules!
DEVCON 2013
Singleton Pattern
What if we bend the rules? ...
object Application extends Configurable { // The functionality of the application goes here ... }
DEVCON 2013
Strategy and Co.
DEVCON 2013
Strategy and Co.
interface Player { void attack(Player enemy); // Other stuff the player does ...
} interface Weapon { void attack(Player enemy); } class AbstractPlayer implements Player { private Weapon weapon;
public setWeapon(Weapon weapon) { this.weapon = weapon; } public void attack(Player enemy) { weapon.attack(enemy); }
} class Axe implements Weapon { ... } class Sword implements Weapon { ... } class Bow implements Weapon { ... }
ü Java is a pure-OOP programming language
ü Everything is modeled using objects
Strategy is fighting against the lack of other mechanism to represent behavior!
DEVCON 2013
Strategy and Co.
What if we have a non-pure OOP language?
class player { public: typedef std::function<void(Player&)> weapon; void set_weapon(weapon& w) { _weapon = w; } void attack(player& enemy) { _weapon(enemy); } private: weapon _weapon; }; void axe(player& enemy) { ... } void sword(player& enemy) { ... } void bow(player& enemy) { ... }
DEVCON 2013
Strategy and Co.
The lack of functions is not a matter exclusive for strategy pattern ü Observer pattern ü Factory (method) pattern ü Adapter pattern ü …
DEVCON 2013
Visitor
DEVCON 2013
Visitor
interface CarElementVisitor { void visit(Wheel wheel); void visit(Engine engine); void visit(Body body); void visit(Car car); } interface CarElement { void accept(CarElementVisitor visitor); } class Wheel implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } } class Engine implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } } class Body implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } }
class Car implements CarElement { public void accept(CarElementVisitor visitor) { for(CarElement elem : elements) elem.accept(visitor); visitor.visit(this); } } class Mechanic implements CarElementVisitor { public void visit(Wheel wheel) { ... } public void visit(Engine engine) { ... } public void visit(Body body) { ... } public void visit(Car car) { ... } }
DEVCON 2013
Visitor
interface CarElementVisitor { void visit(Wheel wheel); void visit(Engine engine); void visit(Body body); void visit(Car car); } class Car implements CarElement { public void accept(CarElementVisitor visitor) { for(CarElement elem : elements) visitor.visit(elem); visitor.visit(this); } }
Why not simply…?
elem is a CarElement, and
visit(CarElement) is not defined in
visitor!
DEVCON 2013
Visitor
That’s why we need to redefine accept() again and again
interface CarElement { void accept(CarElementVisitor visitor); } class Wheel implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } } class Engine implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } } class Body implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } }
Call visit(Wheel w)
Call visit(Engine e)
Call visit(Body b)
DEVCON 2013
Visitor
What if we dispatch the message based on… ü The receiver of the message, and… ü The arguments of the message?
Let me introduce the double dispatch! Visitor pattern is there to provide double dispatch semantics not supported by the language
DEVCON 2013
Conclusions
DEVCON 2013
Conclusions
ü Design patterns are bad ü NOOOOOOOOOOO!!!!!!! ü Design patterns are useful, even when they fight against the
language ü We must learn from our errors and languages must evolve to
avoid them And some opinions ü OOP as implemented by Java is almost over ü Learn Scala
DEVCON 2013
Q&A