TDDB84: Lecture 09 SOLID, Language design, Summary
SOLID Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Depency inversion principle
SOLID Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Depency inversion principle
Single responsibility Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Single responsibility Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Single responsibility Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Open/closed Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Open/closed Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Liskov substitution Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Liskov substitution Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Interface segregation Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Interface segregation Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Depency inversion Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Depency inversion Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Depency inversion Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Depency inversion Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Encapsulate what varies Strive for loosely-coupled design
Too general? Encapsulate what varies Strive for loosely-coupled design
Too general? Encapsulate what varies Strive for loosely-coupled design A consequence of applying SOLID?
Too general? Too trivial? Encapsulate what varies Strive for loosely-coupled design A consequence of applying SOLID?
Language Design vs Design Patterns
Language features Open classes: The ability to redefine classes Metaprogramming: The ability to inspect and manipulate programs and their processes from within the language Multiple dispatch: The ability to select a function based on the runtime types of all arguments First-order functions: The ability to use functions as objects
Open classes
C# Open classes public static class ObjectExtensions {!!! 1.ToXML ();!!! new Person ().ToXML (); public static string ToXML(this object objecttoserialize) { MemoryStream mem=new MemoryStream(); XmlSerializer ser=new XmlSerializer(objectToSerialize.GetType()); ser.serialize(mem,objecttoserialize); ASCIIEncoding ascii=new ASCIIEncoding(); return ascii.getstring(mem.toarray()); }
C# Open classes public static class ObjectExtensions {!!! 1.ToXML ();!!! new Person ().ToXML (); Ruby public static string ToXML(this object objecttoserialize) { MemoryStream mem=new MemoryStream(); XmlSerializer ser=new XmlSerializer(objectToSerialize.GetType()); ser.serialize(mem,objecttoserialize); ASCIIEncoding ascii=new ASCIIEncoding(); return ascii.getstring(mem.toarray()); } class Object def to_xml vars = instance_variables.map do var name=var.to_s.sub('@','') "<#{name}>#{instance_variable_get(var)}</#{name}>".join(" ") "<root>#{vars}</root>" irb(main):081:0> p.to_xml "<root><name>ola</name> <age>34</age></root>" class Person attr_accessor :name, :age p = Person.new p.name = "Ola" p.age = 34
Metaprogramming C# public class FieldMappingConfigurator<T> where T: class, new() { private Configurator Configurator { get; set; } private string FieldName { get; set; } internal FieldMappingConfigurator(string fieldname, Configurator configurator) { Configurator = configurator; FieldName = fieldname; } } public void To<T1>(Expression<Func<T,T1>> propertyselector) { var selectorexpression = (MemberExpression) propertyselector.body; var prop = (PropertyInfo) selectorexpression.member; Configurator.CustomFieldsToPropertiesMap[FieldName]=prop; } GenericDAO<DomainObject>.Configure("some_StoredProcedure").Map("AFieldInTheResultSetReturned").To(s => s.id);
Metaprogramming C# public class FieldMappingConfigurator<T> where T: class, new() { private Configurator Configurator { get; set; } private string FieldName { get; set; } internal FieldMappingConfigurator(string fieldname, Configurator configurator) { Configurator = configurator; FieldName = fieldname; } } public void To<T1>(Expression<Func<T,T1>> propertyselector) { var selectorexpression = (MemberExpression) propertyselector.body; var prop = (PropertyInfo) selectorexpression.member; Configurator.CustomFieldsToPropertiesMap[FieldName]=prop; } GenericDAO<DomainObject>.Configure("some_StoredProcedure").Map("AFieldInTheResultSetReturned").To(s => s.id);
Metaprogramming C# public class FieldMappingConfigurator<T> where T: class, new() { private Configurator Configurator { get; set; } private string FieldName { get; set; } internal FieldMappingConfigurator(string fieldname, Configurator configurator) { Configurator = configurator; FieldName = fieldname; } } public void To<T1>(Expression<Func<T,T1>> propertyselector) { var selectorexpression = (MemberExpression) propertyselector.body; var prop = (PropertyInfo) selectorexpression.member; Configurator.CustomFieldsToPropertiesMap[FieldName]=prop; } GenericDAO<DomainObject>.Configure("some_StoredProcedure").Map("AFieldInTheResultSetReturned").To(s => s.id);
Metaprogramming GenericDAO<DomainObject>.Configure("some_StoredProcedure").Map("AFieldInTheResultSetReturned").To(s => s.id); C# public class FieldMappingConfigurator<T> where T: class, new() { private Configurator Configurator { get; set; } private string FieldName { get; set; } internal FieldMappingConfigurator(string fieldname, Configurator configurator) { Configurator = configurator; FieldName = fieldname; } } public void To<T1>(Expression<Func<T,T1>> propertyselector) { var selectorexpression = (MemberExpression) propertyselector.body; var prop = (PropertyInfo) selectorexpression.member; Configurator.CustomFieldsToPropertiesMap[FieldName]=prop; } Program analysis
Metaprogramming class SetupProjectBuilder class << self def setup_classes @setup_classes = [] Ruby def inherited(sub_class) setup_classes << sub_class def setup_project?(project_file)!setup_class(project_file).nil? def setup_class(project_file) setup_classes.find { c c.project_file_pattern =~ project_file } class VDProjBuilder < SetupProjectBuilder def self.project_file_pattern /\.vdproj$/ [... ]
Metaprogramming class SetupProjectBuilder class << self def setup_classes @setup_classes = [] Ruby def inherited(sub_class) setup_classes << sub_class def setup_project?(project_file)!setup_class(project_file).nil? Process analysis def setup_class(project_file) setup_classes.find { c c.project_file_pattern =~ project_file } class VDProjBuilder < SetupProjectBuilder def self.project_file_pattern /\.vdproj$/ [... ]
Metaprogramming class SetupProjectBuilder class << self Method-related hooks Ruby def setup_classes @setup_classes = [] def inherited(sub_class) setup_classes << sub_class def setup_project?(project_file)!setup_class(project_file).nil? Process analysis def setup_class(project_file) setup_classes.find { c c.project_file_pattern =~ project_file } method_missing method_added singleton_method_added method_removed singleton_method_removed method_undefined singleton_method_undefined Class & Module Hooks inherited app_features included ext_object exted initialize_copy const_missing class VDProjBuilder < SetupProjectBuilder def self.project_file_pattern /\.vdproj$/ [... ]
Metaprogramming class SetupProjectBuilder class << self Method-related hooks Ruby def setup_classes @setup_classes = [] def inherited(sub_class) setup_classes << sub_class def setup_project?(project_file)!setup_class(project_file).nil? Process analysis def setup_class(project_file) setup_classes.find { c c.project_file_pattern =~ project_file } method_missing method_added singleton_method_added method_removed singleton_method_removed method_undefined singleton_method_undefined Class & Module Hooks inherited app_features included ext_object exted initialize_copy const_missing class VDProjBuilder < SetupProjectBuilder def self.project_file_pattern /\.vdproj$/ [... ]
Metaprogramming class SetupProjectBuilder class << self Method-related hooks Ruby def setup_classes @setup_classes = [] def inherited(sub_class) setup_classes << sub_class def setup_project?(project_file)!setup_class(project_file).nil? Process analysis def setup_class(project_file) setup_classes.find { c c.project_file_pattern =~ project_file } method_missing method_added singleton_method_added method_removed singleton_method_removed method_undefined singleton_method_undefined Class & Module Hooks inherited app_features included ext_object exted initialize_copy const_missing class VDProjBuilder < SetupProjectBuilder Factory Method def self.project_file_pattern /\.vdproj$/ [... ]
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name]
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name] class Mail < YamlConf;
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name] class Mail < YamlConf; config/mail.yml from: "john.appleseed@apple.com" to: - "ola.leifler@liu.se" - "tommy.farnqvist@liu.se" host: "smtp.somehost.com"
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name] class Mail < YamlConf; mail = Mail.new do from Conf::Mail.from to Conf::Mail.to subject s body b config/mail.yml from: "john.appleseed@apple.com" to: - "ola.leifler@liu.se" - "tommy.farnqvist@liu.se" host: "smtp.somehost.com"
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name] class Mail < YamlConf; mail = Mail.new do from Conf::Mail.from to Conf::Mail.to subject s body b config/mail.yml from: "john.appleseed@apple.com" to: - "ola.leifler@liu.se" - "tommy.farnqvist@liu.se" host: "smtp.somehost.com"
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name] class Mail < YamlConf; mail = Mail.new do from Conf::Mail.from to Conf::Mail.to subject s body b config/mail.yml from: "john.appleseed@apple.com" to: - "ola.leifler@liu.se" - "tommy.farnqvist@liu.se" host: "smtp.somehost.com"
Metaprogramming in Ruby class YamlConf def conf @conf = load(self.class.simple_name+".yml") # Look up keys in the configuration hash def method_missing(method,*args) method_name=method.to_s conf[method_name] class Mail < YamlConf; mail = Mail.new do from Conf::Mail.from to Conf::Mail.to subject s body b config/mail.yml from: "john.appleseed@apple.com" to: - "ola.leifler@liu.se" - "tommy.farnqvist@liu.se" host: "smtp.somehost.com" Proxy
Metaprogramming in Java public State() { ClassWithState obj = ClassWithState.this; manipulatefields(obj, new FieldManipulator() { @Override public void manipulatefield(object obj, Field field) throws IllegalAccessException { } getstate().put(field.getname(), field.get(obj)); } }); private void manipulatefields(object obj, FieldManipulator fieldmanipulator) { Class<?> cl = obj.getclass(); for (Field field : cl.getdeclaredfields()) { field.setaccessible(true); try { fieldmanipulator.manipulatefield(obj, field); } catch (IllegalArgumentException e) { e.printstacktrace(); } catch (IllegalAccessException e) { e.printstacktrace(); } } }
Metaprogramming in Java public State() { ClassWithState obj = ClassWithState.this; manipulatefields(obj, new FieldManipulator() { @Override public void manipulatefield(object obj, Field field) throws IllegalAccessException { } getstate().put(field.getname(), field.get(obj)); } }); Memento private void manipulatefields(object obj, FieldManipulator fieldmanipulator) { Class<?> cl = obj.getclass(); for (Field field : cl.getdeclaredfields()) { field.setaccessible(true); try { fieldmanipulator.manipulatefield(obj, field); } catch (IllegalArgumentException e) { e.printstacktrace(); } catch (IllegalAccessException e) { e.printstacktrace(); } } }
Metaprogramming in Java @Override public Object invoke(object arg0, Method m, Object[] arg2) throws Throwable { Object result = m.invoke(instance, arg2); if (m.getname().equals("getemployments") && result == null) { } System.out.println(MessageFormat.format( "Trying to access uninstantiated field {0}", m.getname().substring(3))); [ some magic happens ] Method setter = m.getdeclaringclass().getmethod( "setemployments", Collection.class); System.out.println(MessageFormat.format( "Instantiated field {0}", m.getname().substring(3))); setter.invoke(instance, employments); } return m.invoke(instance, arg2);
Metaprogramming in Java @Override public Object invoke(object arg0, Method m, Object[] arg2) throws Throwable { Object result = m.invoke(instance, arg2); if (m.getname().equals("getemployments") && result == null) { } System.out.println(MessageFormat.format( "Trying to access uninstantiated field {0}", m.getname().substring(3))); [ some magic happens ] Method setter = m.getdeclaringclass().getmethod( "setemployments", Collection.class); System.out.println(MessageFormat.format( "Instantiated field {0}", m.getname().substring(3))); setter.invoke(instance, employments); } return m.invoke(instance, arg2); Proxy
Multiple dispatch (defclass duck () ((name :initarg :name :accessor name))) (defclass mallard-duck (duck) ()) (defclass red-duck (duck) ()) (defclass rubber-duck (duck) ()) ;; In another file, we can add flying behavior ;; What design pattern is this an implementation of? (defclass fly-behavior () ()) (defclass fly-with-wings (fly-behavior) ()) (defclass no-fly (fly-behavior) ()) (defgeneric fly (duck fly-behavior) (:documentation "A method to allow ducks to fly") (:method ((d mallard-duck) (b fly-with-wings)) (format t "The mallard duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b fly-with-wings)) (format t "Rubber duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b no-fly)) (format t "Rubber duck ~A is not flying at all" (name d))) )
Multiple dispatch (defclass duck () ((name :initarg :name :accessor name))) (defclass mallard-duck (duck) ()) (defclass red-duck (duck) ()) (defclass rubber-duck (duck) ()) ;; In another file, we can add flying behavior ;; What design pattern is this an implementation of? (defclass fly-behavior () ()) (defclass fly-with-wings (fly-behavior) ()) (defclass no-fly (fly-behavior) ()) (defgeneric fly (duck fly-behavior) (:documentation "A method to allow ducks to fly") (:method ((d mallard-duck) (b fly-with-wings)) (format t "The mallard duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b fly-with-wings)) (format t "Rubber duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b no-fly)) (format t "Rubber duck ~A is not flying at all" (name d))) ) Method description
Multiple dispatch (defclass duck () ((name :initarg :name :accessor name))) (defclass mallard-duck (duck) ()) (defclass red-duck (duck) ()) (defclass rubber-duck (duck) ()) ;; In another file, we can add flying behavior ;; What design pattern is this an implementation of? (defclass fly-behavior () ()) (defclass fly-with-wings (fly-behavior) ()) (defclass no-fly (fly-behavior) ()) (defgeneric fly (duck fly-behavior) (:documentation "A method to allow ducks to fly") (:method ((d mallard-duck) (b fly-with-wings)) (format t "The mallard duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b fly-with-wings)) (format t "Rubber duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b no-fly)) (format t "Rubber duck ~A is not flying at all" (name d))) ) Method description ;; CL-USER> (fly (make-instance 'rubber-duck :name "Ducky") (make-instance 'fly-with-wings)) ;; Rubber duck Ducky is flying with wings! ;; NIL ;; CL-USER> (fly (make-instance 'rubber-duck :name "Ducky") (make-instance 'no-fly)) ;; Rubber duck Ducky is not flying at all
Multiple dispatch (defclass duck () ((name :initarg :name :accessor name))) (defclass mallard-duck (duck) ()) (defclass red-duck (duck) ()) (defclass rubber-duck (duck) ()) ;; In another file, we can add flying behavior ;; What design pattern is this an implementation of? (defclass fly-behavior () ()) (defclass fly-with-wings (fly-behavior) ()) (defclass no-fly (fly-behavior) ()) (defgeneric fly (duck fly-behavior) (:documentation "A method to allow ducks to fly") (:method ((d mallard-duck) (b fly-with-wings)) (format t "The mallard duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b fly-with-wings)) (format t "Rubber duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b no-fly)) (format t "Rubber duck ~A is not flying at all" (name d))) ) Method description Method dispatch ;; CL-USER> (fly (make-instance 'rubber-duck :name "Ducky") (make-instance 'fly-with-wings)) ;; Rubber duck Ducky is flying with wings! ;; NIL ;; CL-USER> (fly (make-instance 'rubber-duck :name "Ducky") (make-instance 'no-fly)) ;; Rubber duck Ducky is not flying at all
Multiple dispatch (defclass duck () ((name :initarg :name :accessor name))) (defclass mallard-duck (duck) ()) (defclass red-duck (duck) ()) (defclass rubber-duck (duck) ()) ;; In another file, we can add flying behavior ;; What design pattern is this an implementation of? (defclass fly-behavior () ()) (defclass fly-with-wings (fly-behavior) ()) (defclass no-fly (fly-behavior) ()) (defgeneric fly (duck fly-behavior) (:documentation "A method to allow ducks to fly") (:method ((d mallard-duck) (b fly-with-wings)) (format t "The mallard duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b fly-with-wings)) (format t "Rubber duck ~A is flying with wings!" (name d))) (:method ((d rubber-duck) (b no-fly)) (format t "Rubber duck ~A is not flying at all" (name d))) ) Method description Method dispatch ;; CL-USER> (fly (make-instance 'rubber-duck :name "Ducky") (make-instance 'fly-with-wings)) ;; Rubber duck Ducky is flying with wings! ;; NIL ;; CL-USER> (fly (make-instance 'rubber-duck :name "Ducky") (make-instance 'no-fly)) ;; Rubber duck Ducky is not flying at all Strategy
(defclass expression () ()) (defclass compound-expression (expression) ((left :initarg :left :accessor left) (operator :initarg :operator :accessor operator) (right :initarg :right :accessor right))) (defclass atomic (expression) ((value :initarg :value :accessor value))) compoundexpression expression atomic ;;;;;;;; Indepently of the classes above, we define a way to ;;;;;;;; perform different operations on the objects of each class ;; What pattern would this correspond in the GoF book? (defgeneric get-value (Expression) (:documentation "Calculates the value of the expression ") (:method ((self compound-expression)) (funcall (operator self)! (get-value (left self))! (get-value (right self)))) (:method ((self atomic)) (value self))) (defvar expression (make-instance 'compound-expression!!! :left (make-instance 'atomic :value 3)!!! :operator #'*!!! :right (make-instance 'atomic :value 4))) (defvar expression2 (make-instance 'compound-expression!!! :left expression!!! :operator #'+!!! :right (make-instance 'atomic :value 5)!!! )) expression2 + expression * 5 (get-value expression2) 3 4
(defclass expression () ()) (defclass compound-expression (expression) ((left :initarg :left :accessor left) (operator :initarg :operator :accessor operator) (right :initarg :right :accessor right))) (defclass atomic (expression) ((value :initarg :value :accessor value))) compoundexpression expression atomic ;;;;;;;; Indepently of the classes above, we define a way to ;;;;;;;; perform different operations on the objects of each class ;; What pattern would this correspond in the GoF book? (defgeneric get-value (Expression) (:documentation "Calculates the value of the expression ") (:method ((self compound-expression)) (funcall (operator self)! (get-value (left self))! (get-value (right self)))) (:method ((self atomic)) (value self))) (defvar expression (make-instance 'compound-expression!!! :left (make-instance 'atomic :value 3)!!! :operator #'*!!! :right (make-instance 'atomic :value 4))) (defvar expression2 (make-instance 'compound-expression!!! :left expression!!! :operator #'+!!! :right (make-instance 'atomic :value 5)!!! )) expression2 + expression * 5 (get-value expression2) 3 4 Visitor
First-order functions C# new List<int> () { 1, 2, 3 }.Select (x => x +2); => { 3, 4, 5 } Ruby [1,2,3].collect { x x+2 } => [3,4,5] Lisp (mapcar #'(lambda (x) (+ x 2)) '(1 2 3)) => (3 4 5)
First-order functions C# new List<int> () { 1, 2, 3 }.Select (x => x +2); => { 3, 4, 5 } Ruby [1,2,3].collect { x x+2 } => [3,4,5] Lisp (mapcar #'(lambda (x) (+ x 2)) '(1 2 3)) => (3 4 5)
First-order functions C# new List<int> () { 1, 2, 3 }.Select (x => x +2); => { 3, 4, 5 } Ruby [1,2,3].collect { x x+2 } => [3,4,5] Lisp (mapcar #'(lambda (x) (+ x 2)) '(1 2 3)) => (3 4 5)
First-order functions C# new List<int> () { 1, 2, 3 }.Select (x => x +2); => { 3, 4, 5 } Ruby [1,2,3].collect { x x+2 } => [3,4,5] Lisp (mapcar #'(lambda (x) (+ x 2)) '(1 2 3)) => (3 4 5)
First-order functions C# new List<int> () { 1, 2, 3 }.Select (x => x +2); => { 3, 4, 5 } Ruby [1,2,3].collect { x x+2 } => [3,4,5] Lisp (mapcar #'(lambda (x) (+ x 2)) '(1 2 3)) => (3 4 5) Strategy
Open classes vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
Open classes vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
Metaprogramming vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
Metaprogramming vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
Multiple dispatch vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
Multiple dispatch vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
First-order functions vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
First-order functions vs Design Patterns Creational Factory method Abstract Factory Singleton Prototype Strategy Builder Structural Decorator Facade Composite Proxy Flyweight Bridge Adapter Behavioral State Command Template method Iterator Visitor Interpreter Mediator Chain of responsibility Observer Memento Highlighted patterns simplified
Summary
What is Good Design?
Encapsulate what varies Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Don t call us, we ll call you Dep on abstractions, do not dep on concrete classes Classes should only have one reason to change Strive for loosely-coupled design
Or...
Or... Testable programs
Or... Testable programs Changeable programs
Or... Testable programs Changeable programs
Or... Testable programs Changeable programs Test Change
What is a Design Pattern?
What is a Design Pattern? Why are there Design Patterns?
What is a Design Pattern? Why are there Design Patterns? How are Design Patterns used/recognized?
Why
Why 1. There are OO Programming Languages
Why 1. There are OO Programming Languages 2. There are Common Problems
Why 1. There are OO Programming Languages 2. There are Common Problems 3. There are Design Principles
Why 1. There are OO Programming Languages 2. There are Common Problems 3. There are Design Principles 1+2+3 = Design Pattern
How
How 1. There are Structure Diagrams
How 1. There are Structure Diagrams 2. There are A Bunch of Other Attributes
How 1. There are Structure Diagrams 2. There are A Bunch of Other Attributes 1+2 = Design Pattern
Other Patterns
Other Patterns Simpleton The Simpleton Pattern is an extremely complex pattern used for the most trivial of tasks. The Simpleton is an accurate indicator of the skill level of its creator.
Other Patterns Simpleton The Simpleton Pattern is an extremely complex pattern used for the most trivial of tasks. The Simpleton is an accurate indicator of the skill level of its creator. Commando The Commando Pattern is used to get in and out quick, and get the job done. This pattern can break any encapsulation to accomplish its mission. It takes no prisoners.
Other Patterns Simpleton The Simpleton Pattern is an extremely complex pattern used for the most trivial of tasks. The Simpleton is an accurate indicator of the skill level of its creator. Commando The Commando Pattern is used to get in and out quick, and get the job done. This pattern can break any encapsulation to accomplish its mission. It takes no prisoners. http://franksworld.com/blog/archive/2005/01/04/600.aspx
The Exam
Oct 25th 8-12 Bring written notes & the books. Justify all your reasoning. Good luck!
Thank you!