soen6461 software design methodologies
play

SOEN6461: Software Design Methodologies Yann-Gal Guhneuc Yann-Gal - PowerPoint PPT Presentation

SOEN6461: Software Design Methodologies Yann-Gal Guhneuc Yann-Gal Guhneuc Encapsulation, inheritance and types, polymorphism (overriding/overloading), abstraction and types This work is licensed under a Creative Commons


  1. Inheritance, Types  Prototype-based, typically JavaScript – “Subtyping” function Type() { } Type.prototype.foo = function foo() { throw new Error("This is an abstract method!"); var type = }; new Type(); Type.prototype.bar = function bar() { type.foo(); throw new Error("This is an abstract method!"); type.bar(); }; function SubType() { } SubType.prototype = new Type(); SubType.prototype.constructor = SubType; SubType.prototype.foo = function foo() { document.write("foo()<br>"); var subtype = }; new SubType(); SubType.prototype.bar = function bar() { subtype.foo(); document.write("bar()<br>"); subtype.bar(); }; 32/128

  2. Inheritance, Types  Reuse and subtyping combined function AbstractMeasure() { } AbstractMeasure.prototype.getValue = function getValue() { document.write("Some code before...<br>"); return this .getRealValue(); }; AbstractMeasure.prototype.getRealValue = function getRealValue() { throw new Error("Abstract method!"); }; function Length() { } Length.prototype = new AbstractMeasure(); Length.prototype.constructor = Length; Length.prototype.getRealValue = function getRealValue() { document.write("Specific code.<br>"); return 1; }; 33/128

  3. No real distinction between Inheritance, Types reuse and “subtyping”  Reuse and subtyping combined function AbstractMeasure() { } AbstractMeasure.prototype.getValue = function getValue() { document.write("Some code before...<br>"); return this .getRealValue(); }; AbstractMeasure.prototype.getRealValue = function getRealValue() { throw new Error("Abstract method!"); }; function Length() { } Length.prototype = new AbstractMeasure(); Length.prototype.constructor = Length; Length.prototype.getRealValue = function getRealValue() { document.write("Specific code.<br>"); return 1; }; 34/128

  4. Inheritance, Types  Java vs. JavaScript – Make no mistake: JavaScript is no less “powerful” or “clean” than Java! – Different paradigms • Class + Imperative + Strongly-typed • Prototype + Functional + Dynamically-typed – Different implementations of the paradigms • Visibility • Pairs name + value 35/128

  5. Polymorphism Problem: change behaviour of concrete objects Solution: polymorphism  Definition – Subtype polymorphism, almost universally called polymorphism in object-oriented programming – The ability to create a variable, a function, or an object that has more than one form – Superset of overloading, overriding 36/128

  6. Overriding  Definition – A language feature that allows a subclass or a child class to provide a specific implementation of a method that is already provided by one of its super / parent classes 37/128

  7. Overriding  Class-based, typically Java public class SuperClass { public void foo() { System. out.println("One implementation."); } } public class SubClass extends SuperClass { public void foo() { super .foo(); System. out.println("Another implementation."); } } 38/128

  8. Overriding  Class-based, typically Java – Declared type vs. Concrete type – Overriding is resolved by the dynamic type of the receiver , not its static type public class Main { public static void main( final String[] args) throws InstantiationException, IllegalAccessException { final SuperClass superClass = new SubClass(); superClass.foo(); final SubClass subClass = new SubClass(); ((SuperClass) subClass).foo(); ((SuperClass) subClass.getClass().getSuperclass().newInstance()).foo(); } } 39/128

  9. Distinction between declared type and Overriding concrete type  Class-based, typically Java – Declared type vs. Concrete type – Overriding is resolved by the dynamic type of the receiver , not its static type public class Main { public static void main( final String[] args) throws InstantiationException, IllegalAccessException { final SuperClass superClass = new SubClass(); superClass.foo(); final SubClass subClass = new SubClass(); ((SuperClass) subClass).foo(); ((SuperClass) subClass.getClass().getSuperclass().newInstance()).foo(); } } 40/128

  10. Distinction between declared type and Overriding concrete type Runtime dispatch  Class-based, typically Java – Declared type vs. Concrete type – Overriding is resolved by the dynamic type of the receiver , not its static type public class Main { public static void main( final String[] args) throws InstantiationException, IllegalAccessException { final SuperClass superClass = new SubClass(); superClass.foo(); final SubClass subClass = new SubClass(); ((SuperClass) subClass).foo(); ((SuperClass) subClass.getClass().getSuperclass().newInstance()).foo(); } } 41/128

  11. Distinction between declared type and Overriding concrete type Runtime dispatch  Class-based, typically Java Reflection – Declared type vs. Concrete type – Overriding is resolved by the dynamic type of the receiver , not its static type public class Main { public static void main( final String[] args) throws InstantiationException, IllegalAccessException { final SuperClass superClass = new SubClass(); superClass.foo(); final SubClass subClass = new SubClass(); ((SuperClass) subClass).foo(); ((SuperClass) subClass.getClass().getSuperclass().newInstance()).foo(); } } 42/128

  12. Overriding  Prototype-based, typically JavaScript function SuperClass() { } SuperClass.prototype.foo = function foo() { document.write("One implementation...<br>"); }; function SubClass() { } SubClass.prototype = new SuperClass(); SubClass.prototype.constructor = SubClass; SubClass.prototype.parent = SuperClass.prototype; SubClass.prototype.foo = function foo() { this .parent.foo.call( this ); document.write("Another implementation...<br>"); }; – Declared type vs. concrete type var subClass = new SubClass(); subClass.foo(); 43/128

  13. No type declaration  Unlike Java! Overriding  Prototype-based, typically JavaScript function SuperClass() { } SuperClass.prototype.foo = function foo() { document.write("One implementation...<br>"); }; function SubClass() { } SubClass.prototype = new SuperClass(); SubClass.prototype.constructor = SubClass; SubClass.prototype.parent = SuperClass.prototype; SubClass.prototype.foo = function foo() { this .parent.foo.call( this ); document.write("Another implementation...<br>"); }; – Declared type vs. concrete type var subClass = new SubClass(); subClass.foo(); 44/128

  14. No type declaration  Unlike Java! Overriding No super  Unlike Java!  Prototype-based, typically JavaScript function SuperClass() { } SuperClass.prototype.foo = function foo() { document.write("One implementation...<br>"); }; function SubClass() { } SubClass.prototype = new SuperClass(); SubClass.prototype.constructor = SubClass; SubClass.prototype.parent = SuperClass.prototype; SubClass.prototype.foo = function foo() { this .parent.foo.call( this ); document.write("Another implementation...<br>"); }; – Declared type vs. concrete type var subClass = new SubClass(); subClass.foo(); 45/128

  15. Overriding  Java vs. JavaScript – Make no mistake: JavaScript is no less “powerful” or “clean” than Java! – Different paradigms • Class + Imperative + Strongly-typed • Prototype + Functional + Dynamically-typed – Different implementations of the paradigms • Runtime method dispatch • Possibility to change the context of a call 46/128

  16. Overloading  Definition – Methods that have the same name but different signatures inside the same class or a class hierarchy 47/128

  17. Overloading  Class-based, typically Java public class Point { public boolean equals(final Object anObject) { System. out.println("One implementation."); return false; } public boolean equals(final Point aPoint) { System. out.println("Another implementation."); return false; } } public class Main { public static void main(final String[] args) { final Point p1 = new Point(); final Point p2 = new Point(); final Object o = p1; System. out.println(p1.equals(p2)); System. out.println(o.equals(p2)); System. out.println(p1.equals(o)); } } 48/128

  18. Overloading  Class-based, typically Java public class Point { public boolean equals(final Object anObject) { System. out.println("One implementation."); return false; } public boolean equals(final Point aPoint) { System. out.println("Another implementation."); return false; } } public class Main { public static void main(final String[] args) { final Point p1 = new Point(); Another implementation. final Point p2 = new Point(); false final Object o = p1; System. out.println(p1.equals(p2)); System. out.println(o.equals(p2)); System. out.println(p1.equals(o)); } } 49/128

  19. Overloading  Class-based, typically Java public class Point { public boolean equals(final Object anObject) { System. out.println("One implementation."); return false; } public boolean equals(final Point aPoint) { System. out.println("Another implementation."); return false; } } public class Main { public static void main(final String[] args) { final Point p1 = new Point(); Another implementation. final Point p2 = new Point(); false final Object o = p1; One implementation. System. out.println(p1.equals(p2)); false System. out.println(o.equals(p2)); System. out.println(p1.equals(o)); } } 50/128

  20. Overloading  Class-based, typically Java public class Point { public boolean equals(final Object anObject) { System. out.println("One implementation."); return false; } public boolean equals(final Point aPoint) { System. out.println("Another implementation."); return false; } } public class Main { public static void main(final String[] args) { final Point p1 = new Point(); Another implementation. final Point p2 = new Point(); false final Object o = p1; One implementation. System. out.println(p1.equals(p2)); false System. out.println(o.equals(p2)); One implementation. System. out.println(p1.equals(o)); false } } 51/128

  21. Overloading  Class-based, typically Java – The equals() method in Point takes a Point instead of an Object as an argument – It does not override equals in Object – It is just an overloaded alternative – Overloading is resolved by the static type of the argument , not its run-time type 52/128

  22. Overloading  Class-based, typically Java – Using the static type of the argument is natural in a strongly-typed language... – Else how could the program compile? final Point p1 = new Point(); final Object o = p1; System. out.println(o.equals(p2)); 53/128

  23. // Compiled from Main.java (version 1.6 : 50.0, Overloading super bit) public class ca.concordial.soeb6461.overloading.Main { // Method descriptor #6 ()V // Stack: 1, Locals: 1 public Main();  Class-based, typically 0 aload_0 [this] Java 1 invokespecial java.lang.Object() 4 return – Using the static type of […] the argument is natural in a strongly-typed // Method descriptor #15 ([Ljava/lang/String;)V // Stack: 3, Locals: 4 language... public static void main(java.lang.String[] args); – Else how could the […] 32 aload_3 [o] program compile? 33 aload_2 [p2] 34 invokevirtual java.lang.Object.equals(java.lang.Object) : boolean final Point p1 = new Point(); 37 invokevirtual final Object o = p1; java.io.PrintStream.println(boolean) : void System. out.println(o.equals(p2)); 40 getstatic java.lang.System.out : java.io.PrintStream 54/128

  24. Overloading  Prototype-based, typically JavaScript – The issue here is really that JavaScript is dynamically-typed – Overloading just does not make sense ! 55/128

  25. Overloading  Prototype-based, typically JavaScript – Implementing the look-up table manually // addMethod - By John Resig (MIT Licensed) function addMethod(object, name, fn){ var old = object[ name ]; object[ name ] = function (){ if ( fn.length == arguments.length ) return fn.apply( this , arguments ); else if ( typeof old == 'function' ) return old.apply( this , arguments ); }; } When control enters the execution context of a function an arguments object is created. The arguments object has an array-like structure with an indexed property for each passed argument and a length property equal to the total number of parameters supplied by the caller. 56/128

  26. Overloading  Prototype-based, typically JavaScript – Implementing the look-up table manually function Users(){} addMethod(Users.prototype, "find", function(){ // Find all users... }); addMethod(Users.prototype, "find", function(name){ // Find a user by name }); addMethod(Users.prototype, "find", function(first, last){ // Find a user by first and last name }); var users = new Users(); users.find(); // Finds all users.find("John"); // Finds users by name users.find("John", "Resig"); // Finds users by first and last name users.find("John", "E", "Resig"); // Does nothing 57/128

  27. Overloading  Java vs. JavaScript – Make no mistake: JavaScript is no less “powerful” or “clean” than Java! – Different paradigms • Class + Imperative + Strongly-typed • Prototype + Functional + Dynamically-typed – Different implementations of the paradigms • Static method dispatch • Dispatch based on name and number of arguments 58/128

  28. Polymorphism Problem: change behaviour of concrete objects Solution: polymorphism  Definition (recalled) – Subtype polymorphism, almost universally called polymorphism in object-oriented programming – The ability to create a variable, a function, or an object that has more than one form – Superset of overloading, overriding 59/128

  29. Polymorphism  Definition – Subtype polymorphism is all about type-safety and the “contract” between a superclass and its subclasses – It is all about pre- and post-conditions • And directly related to co- and contra-variance 60/128

  30. 61/128

  31. Polymorphism – Liskov’s Substitution Principle  Barbara Liskov – Born 7 November 1939 Barbara Liskov *1939 – Mother of the Liskov’s substitution principle – IEEE J. von Neumann Medal in 2004 – ACM Turing Award in 2008 – Cf. http://en.wikipedia.org/wiki/ Liskov_substitution_principle 62/128

  32. Polymorphism – Liskov’s Substitution Principle  Liskov’s substitution principle – Context • 1987 – Object-oriented programming is increasingly popular – Principle • Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T 63/128

  33. Polymorphism – Liskov’s Substitution Principle – Principle (cont’d) • Behavioural sub-typing is different and stronger than the concept of sub-typing in type theory • In type theory – Contravariance of parameters: a parameter of type T can accept object of type S, where S is a sub-type of T – Covariance of return type: the return type can be “enlarged” from T to S • In addition – Pre-conditions cannot be stronger in a sub-type – Post-conditions cannot be weaker in a sub-type – The sub-type S must preserve the invariants of type T 64/128

  34. Polymorphism – Liskov’s Substitution Principle  Definition – If S is a subtype of T , then objects of type T may be replaced with objects of type S (objects of type S may be substitutes for objects of type T ) without altering any of the desirable properties of S (correctness, task, etc.) T P S 65/128

  35. Polymorphism – Liskov’s Substitution Principle  This principle defines the notions of generalization/specialization formally  Class S is correctly defined as a specialization of T if the following are true – For each object s of class S there is an object t of class T such that the expected behavior of any program P defined in terms of T is unchanged if s is substituted for t  Then – S is a said to be a subtype of T – Any instance of S can stand for an instance of T without any undesired effect on client classes – Any future extension (new subclasses) will not affect existing clients From Giuliano Antoniol’s slides INF6305 66/128

  36. Polymorphism – Liskov’s Substitution Principle class Rectangle : public Shape { class Square : public Rectangle { private: int w, h; public: public: void set_width(int w) { virtual void set_width(int wi) { Rectangle::set_height(w); w=wi; Rectangle::set_width(w); } } virtual void set_height(int he) { void set_height(int h) { h=he; set_width(h); } } } } void foo(Rectangle *r) { // This is the client r->set_width(5); r->set_height(4); assert((r->get_width()*r->get_height()) == 20); // Oracle } • If r is instantiated at run time with an instance of square, behaviour observed by client is different ( width*height == 16 ) • Observed behaviour unexpected and may lead to problems • Square should be defined as subclass of Shape , not Rectangle From Giuliano Antoniol’s slides for INF6305. 67/128

  37. Polymorphism – Liskov’s Substitution Principle  Class S is correctly defined as a specialization of T then we say that S is compatible with T T P S 68/128

  38. Polymorphism  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); } } class SubClass extends SuperClass { String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 69/128

  39. Polymorphism  Class-based, typically Java final SuperClass superClass = new SubClass(); final SubClass subClass = new SubClass(); 70/128

  40. Polymorphism  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); } } class SubClass extends SuperClass { String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 71/128

  41. Covariance of return type  Objects returned by getSomething Polymorphism in any subclass are always compatible with that expected by the superclass  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); } } class SubClass extends SuperClass { String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 72/128

  42. Polymorphism  Class-based, typically Java class SuperClass { String getSomething() { return new Object(); } } class SubClass extends SuperClass { Object getSomething() { return new String(); } } public class ContravarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); // This whole piece of code is not legal in Java! For example only. final String result = superClass.getSomething(); } } 73/128

  43. If contavariance of return type  Objects returned by getSomething Polymorphism in a subclass would not be compatible with that expected by the superclass  Class-based, typically Java class SuperClass { String getSomething() { return new Object(); } } class SubClass extends SuperClass { Object getSomething() { return new String(); } } public class ContravarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); // This whole piece of code is not legal in Java! For example only. final String result = superClass.getSomething(); } } 74/128

  44. Polymorphism  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); } } class SubClass extends SuperClass { String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 75/128

  45. Post-conditions in the subtype must Polymorphism be the same as or stronger than in the supertype  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); } } class SubClass extends SuperClass { String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 76/128

  46. Post-conditions in the subtype must Polymorphism be the same as or stronger than in the supertype  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); Post-condition } } class SubClass extends SuperClass { String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 77/128

  47. Post-conditions in the subtype must Polymorphism be the same as or stronger than in the supertype  Class-based, typically Java class SuperClass { Object getSomething() { return new Object(); Post-condition } } class SubClass extends SuperClass { Covariance String getSomething() { return new String(); } } public class CovarianceOfReturnTypes { public static void main( final String[] args) { final SuperClass superClass = new SubClass(); System. out .println( Object. class .isAssignableFrom(superClass.getSomething().getClass())); } } 78/128

  48. Polymorphism  Class-based, typically Java class SuperClass { void getSomething( final String aParameter) { System. out .println("One implementation..."); } } class SubClass extends SuperClass { void getSomething( final Object aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); subClass.getSomething( new Object()); subClass.getSomething(""); } } 79/128

  49. Contravariance of arguments types  Objects used by getSomething in Polymorphism any subclass are always narrower to allow calling the super method  Class-based, typically Java class SuperClass { void getSomething( final String aParameter) { System. out .println("One implementation..."); } } class SubClass extends SuperClass { void getSomething( final Object aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); subClass.getSomething( new Object()); subClass.getSomething(""); } } 80/128

  50. Polymorphism  Class-based, typically Java class SuperClass { void getSomething( final Object aParameter) { System. out .println("One implementation..."); } } class SubClass extends SuperClass { void getSomething( final String aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); // This piece of code is not legal in Java! For example only. subClass.getSomething(""); } } 81/128

  51. Covariance of arguments types  Objects used by getSomething in Polymorphism any subclass would confuse the compiler: which method to use?  Class-based, typically Java class SuperClass { void getSomething( final Object aParameter) { System. out .println("One implementation..."); } } class SubClass extends SuperClass { void getSomething( final String aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); // This piece of code is not legal in Java! For example only. subClass.getSomething(""); } } 82/128

  52. Polymorphism  Class-based, typically Java class SuperClass { void getSomething( final String aParameter) { System. out .println("One implementation..."); } } class SubClass extends SuperClass { void getSomething( final Object aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); subClass.getSomething( new Object()); subClass.getSomething(""); } } 83/128

  53. Pre-conditions in the subtype must be Polymorphism the same as or weaker than in the supertype  Class-based, typically Java class SuperClass { void getSomething( final String aParameter) { System. out .println("One implementation..."); } } class SubClass extends SuperClass { void getSomething( final Object aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); subClass.getSomething( new Object()); subClass.getSomething(""); } } 84/128

  54. Pre-conditions in the subtype must be Polymorphism the same as or weaker than in the supertype  Class-based, typically Java class SuperClass { void getSomething( final String aParameter) { System. out .println("One implementation..."); Pre-condition } } class SubClass extends SuperClass { void getSomething( final Object aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); subClass.getSomething( new Object()); subClass.getSomething(""); } } 85/128

  55. Pre-conditions in the subtype must be Polymorphism the same as or weaker than in the supertype  Class-based, typically Java class SuperClass { void getSomething( final String aParameter) { System. out .println("One implementation..."); Pre-condition } } class SubClass extends SuperClass { Contravariance void getSomething( final Object aParameter) { System. out .println("Another implementation..."); } } public class ContravarianceOfArgumentTypes { public static void main( final String[] args) { final SubClass subClass = new SubClass(); subClass.getSomething( new Object()); subClass.getSomething(""); } } 86/128

  56. Polymorphism  Contra-variance in more depth…  Thank you http://www.jdoodle.com , Firefox Abduction!, and Eclipse compilers 87/128

  57. 88/128

  58. with v1.3 89/128

  59. 90/128

  60. 91/128

  61. 92/128 https://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29

  62. Not Another implementation… Another implementation… 93/128 https://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29

  63. 94/128

  64. Valid! Valid! 95/128

  65. 96/128

  66. Workaround! 97/128

  67. 98/128 https://stackoverflow.com/questions/2995926/why-is-there-no-parameter-contra-variance-for-overriding

  68. 99/128 Thank you to Willian Flageol for the example

  69. 100/128 https://underscore.io/blog/posts/2015/11/04/late-binding-and-overloading.html

Recommend


More recommend