Lectures 35-41 (Set 7 and XC)
Interface Segregation Principle
"Clients should not be forced to depend upon interfaces that they do not use."
What relationship types do classes exhibit?
"Has-A" relationships with its own attributes & state "Is-A" relationships with common ancestors that share attributes & state
Liskov Substitution Principle (the ****ing quote)
"Let Phi(x) be a property provable about objects x of type T. Then Phi(y) should be true for objects y of type S where S is a subtype of T." - Barbara Liskov
Design Principle
"Program to an interface, not an implementation" Leverage polymorphism - rely only on what operations can be done - more maintainable - can change behavior at run time
SOLID Principles (recap but this time from lecture 40)
"Program to an interface, not an implementation." 1. No variable should hold a reference to a concrete class. - Liskov Substitution: hold reference to interface type - Leverages runtime polymorphism 2. No class should derive from a concrete class. - Dependency Inversion: If deriving from a concrete class, then depending upon an abstract interface instead. - Open/Closed: Interfaces are closed for modification but open for extension by adding additional interface methods 3. No method should override an implemented method of any of its base classes. - Dependency Inversion: If overriding an implemented method, then base class wasn't an abstraction. Methods implemented in base class are meant to be shared with all subclasses
Open/Closed Principle
"Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification."
Dependency Inversion Principle
1. High-level modules should not depend on low-level modules. Both should depend on abstractions. 2. Abstractions should not depend on details. Details should depend on abstractions. In other words... Depend upon abstractions. Do not depend upon concrete classes
Example of Liskov Substitution
A Square is a Rectangle - "is a" = inheritance - Square subtypes Rectangle By Liskov Substitution, a program using Rectangle should be able to be replaced with Square with no side effect - setHeigh() & setWidth() don't make sense because changing one changes the other But not all Rectangles are Squares
What is a class?
A class is a blueprint
Interfaces
Abstract Class with ONLY abstract functions - Declares what should be done, not how it should be done
Interfaces (recap)
Abstract class comprised of only abstract functions
What is an object?
An object is an instance of the class. An object provides value for the data members of a class
Polymorphism Concerns
Class Cast Error - Compiler Error! Polymorphism checked at compile-time
Abstract Class (can have more than just abstract functions)
Class with at least one abstract function and: Data members to track state OR Non-abstract functions
Abstract Classes
Class with at least one abstract function is an Abstract Class - Cannot instantiate Abstract Classes
Open for Extension
Classes can be inherited from Interfaces can be implemented In C++ by default - classes are open
Virtual Classes
Classes with virtual functions need a virtual destructor - when deleting pointer, need to delete subtype object Explicitly declare destructor as virtual
How do you represent other things (that are complex?)
Create a class to represent a complex thing - A class encapsulates attributes (variables) and behavior (functions) of real world things attributes, behaviors, abstraction!
Inheritance
Derived Class "Is-A" Base Class Derived Class extends Base Class - Inherits public & protected members from Base Class
Multiple Inheritance Concern
Diamond Problem (see Lecture 36 slides) - inheriting the same function with the same parameters from multiple parent classes
Inheritance OR Composition?
Does TypeB want to expose the complete interface (all public methods) of TypeA such that TypeB can be used where TypeA is expected? - Liskov Substitution - Use Inheritance A Cessna biplane will expose the complete interface of an Airplane. Cessna derives from Airplane. Does TypeB only want some/part of the behavior exposed of TypeA? - Use Composition A Bird needs only the fly behavior of an Airplane. Extract the fly behavior out as an interface and make it a member of both classes.
Weighted Undirected Graph
Doesn't have a set direction but still has different path lengths
Closed for Modification (classes)
Don't change original class Can mark classes as final that cannot be inherited from class A { public: virtual void foo() { cout << "A::foo()" << endl; } }; class B final : public A { public: void foo() final { cout << "B::foo()" << endl; } }; // class C : public B { // B cannot be inherited from // // since it is closed // };
Closed for Modification (functions)
Don't change original class Can mark functions that cannot be overridden as final class A { public: virtual void foo() { cout << "A::foo()" << endl; } }; class B : public A { public: void foo() final { cout << "B::foo()" << endl; } }; class C : public B { public: // void foo() { cout << "C::foo()" << endl; } // B::foo() is final // can't be overridden };
When should you use which type of inheritance?
Favor only using public/private Have good reason for using protected Better solutions exist that we'll soon cover
Good practices for Open/Closed Principle
Good Practice: Implement interfaces Don't extend classes, unless you can ensure the next principle... (Liskov Substitution Principle)
Why single responsibility principle?
If multiple responsibilities, needs to be modified more frequently == harder to maintain One responsibility - easier to explain - reduces number of bugs - improves development speed Don't take to extreme! Don't make a class with one function - Then you'd need to use too many objects to accomplish anything
Object-Oriented Programming
Imperative Programming where program state is encapsulated in a series of objects - only objects can manipulate their own state Programming paradigm that groups attributes and behaviors into a class Program to the domain - user terminology and objects that are present in the field
Run Time Polymorphism
Implementation is resolved by type of object - type is dynamic - known at run time
Compile Time Polymorphism
Implementation tied to type of object - type is static - known at compile time
Minimum Spanning Tree
Nodes point out in specific paths from a central node - not all connected at the edges
Singly Linked List
Nodes with One Pointer
Binary Tree
Nodes with Three Pointers (refer to Lecture 41 for diagrams)
Doubly Linked List
Nodes with Two Pointers
Directed Acyclic Graph (DAG)
Nodes with n Pointers (refer to Lecture 41)
Weighted Directed Acyclic Graph
Nodes with n Pointers that have different path lengths.
Subtype Polymorphism (recounting it in the next lecture)
Object can behave as both derived class type or base class type Type of object determined at compile time Children can override parent method
Liskov Substitution Principle
Objects of superclass shall be replaceable with objects of its subclasses without breaking the application Objects of the subclass behave in the same way as objects of the superclass - Overridden method needs to accept same input parameters. Cannot enforce stricter validation rules - Overridden method needs to return same values. Can be subclass or subset of valid values
Dependency Inversion Principle should already be enforced when:
Open/Closed Principle and Liskov Substitution Principle
Polymorphism (example and definition)
Overloaded Functions & Templates cout << remainder(9, 5) << endl; // prints 4 cout << remainder(9.0f, 5.0f) << endl; // prints 0.8 // ... wordList.pushBack( "polymorphism" ); // adds a string wordCounts.pushBack( 2 ); // adds an int At compile-time, which form to use is known
Overloading Functions
Overloaded functions - Multiple functions have same identifier but different parameters
Ad-Hoc Polymorphism Example
Overloaded functions: int remainder(int numerator, int denominator) { return numerator % denominator; } float remainder(float numerator, float denominator) { return (numerator / denominator) - (int)(numerator / denominator); } // ... cout << remainder(9, 5) << endl; // prints 4 cout << remainder(9.0f, 5.0f) << endl; // prints 0.8 remainder() has two forms
Overriding Functions
Overridden Functions - Derived Class has member function with same function name and signature as Base Class The Derived Class implementation overrides the Base Class implementation overrides the Base Class implementation and takes precedence - Resolve bottom-up
Design Principles
Program to an interface, not an implementation SOLID Principles - Single Responsibility Principle - Interface Segregation Principle
Single Responsibility Principle
Saw with functions "A class should have one, and only one, reason to change." A class (or function) should have only one purpose.
SOLID Principles
Set of design principles for object-oriented software development S - Single Responsibility Principle O - Open/Closed Principle L - Liskov Substitution Principle I - Interface Segregation Principle D - Dependency Inversion
Multiple Inheritance
Shape is both Drawable & Transformable - "Multiple Inheritance" Polymorphism in action!!
Parametric Polymorphism Example
Templates (Classes and/or Functions) class LinkedList { public: void pushBack(const T); // ... private: Node<T>* mpHead; // ... }; // ... LinkedList< string > wordList; wordList.pushBack( "polymorphism" ); // adds a string LinkedList< int > wordCounts; wordCounts.pushBack( 2 ); // adds an int LinkedList has two behaviors
Overridden Functions
To call a specific form, either - cast object type ( (Animal)odie.speak(); ) or use scope resolution ( odie.Dog::speak(); )
Creating a Class Diagram
Uses Unified Modeling Language (UML) to show structure of a class. Lists attributes and behaviors of a class. (Refer to pics from slides)
Pure Virtual Functions
Virtual Function with no default implementation - Pure Virtual Function == Abstract Function (virtual type function() = 0;)
Virtual Functions
Virtual Functions act as "function pointer" Provide a default implementation Subtype overrides parent implementation
Runtime Polymorphism (recap)
Virtual function implementations bound at run time based on pointer object type
"Pure Virtual Function" == Abstract Function (recap)
Virtual function with no default implementation Abstract class - cannot instantiate
Polymorphism
having many forms/behaviors
Subtype Polymorphism (Garfield and Odie animal example)
odie is a Dog and an Animal - Can exhibit behaviors of different types At compile-time, form & behavior is known
Private class access modifier
private: access inside base class
Protected class access modifier
protected: access inside base & inside derived class
What are the types of Inheritance?
public inheritance protected inheritance private inheritance (look at the inheritance access chart from lecture 35)
Public class access modifier
public: can be accessed inside & outside base class