module01-object-oriented.programming.in.python
module01-object-oriented.programming.in.python
MODULE 1
1
Objects
object = state + behavior
“An object has state, behavior, and identity; the structure and behavior of
similar objects are defined in their common class.”
(Booch Object Solutions page 305)
Objects:
> Have identity
> Are an instance of only one class
> Have attribute values that are unique to that object
> Have methods that are common to the class
2
Objects: Example
Classes
A class is a blueprint or prototype from which objects are created. (The Java
Tutorials)
Classes provide:
> The metadata for attributes
> The signature for methods
> The implementation of the methods (usually)
> The constructors to initialize attributes at creation time
4
Classes: Example
Abstraction
In OO software, the concept of abstraction enables you to create a simplified, but
relevant view of a real world object within the context of the problem and
solution domains.
> The abstraction object is a representation of the real world object with
irrelevant (within the context of the system) behavior and data removed.
> The abstraction object is a representation of the real world object with
currently irrelevant (within the context of the view) behavior and data hidden.
6
Abstraction: Example
Encapsulation
Encapsulation means “to enclose in or as if in a capsule” (Webster New
Collegiate Dictionary)
> Encapsulation is essential to an object. An object is a capsule that holds the
object’s internal state within its boundary.
> In most OO languages, the term encapsulation also includes information hiding,
which can be defined as: “hide implementation details behind a set of non-
private methods”.
8
Encapsulation
> Black-Box Design
class
object
private
public
Encapsulation: Example
10
Defining a Class
11
Defining a Class
12
Defining a Class
13
14
Read-Write Property
15
Read-Write Property
16
18
17
Special Method __repr__
Information Hiding
19
Inheritance
Inheritance is “a mechanism whereby a class is defined in reference to others,
adding all their features to its own.” (Meyer page 1197)
Features of inheritance:
> Attributes and methods from the superclass are included in the subclass.
> Subclass methods can override superclass methods.
> The following conditions must be true for the inheritance relationship to be
plausible:
– A subclass object is a (is a kind of) the superclass object.
– Inheritance should conform to Liskov’s Substitution Principle (LSP).
20
Inheritance
> Specific OO languages allow either of the following:
– Single inheritance, which allows a class to directly inherit from only one
superclass (for example, Java).
– Multiple inheritance, which allows a class to directly inherit from one or
more super-classes (for example, C++, Python).
21
Inheritance: Example
22
Inheritance: Example
23
Inheritance: Example
24
Inheritance: Example
25
26
Testing the “is a” Relationship
27
Polymorphism
28
Operator Overloading
> Method-call notation can be cumbersome for certain kinds of operations, such
as arithmetic.
> In these cases, it would be more convenient to use Python’s rich set of built-in
operators.
29
31
32
Operator Overloading Example: Fraction
33
34
Operator Overloading Example: Fraction
__floordiv__
__truediv__
35
36
Objectives
Upon completion of this module, you should be able to:
> Describe the important object-oriented (OO) concepts
> Describe the fundamental OO terminology
37
38
Examining Object Orientation
“Software systems perform certain actions on objects of certain types; to
obtain flexible and reusable systems, it is better to base their structure on the
objects types than on the actions.” (Meyer page vi)
OO concepts affect the following issues:
> Software complexity
> Software decomposition
> Software costs
39
Software Complexity
Complex systems have the following characteristics:
> They have a hierarchical structure.
> The choice of which components are primitive in the system is arbitrary.
> A system can be split by intra- and inter-component relationships. This
separation of concerns enables you to study each part in relative isolation.
> Complex systems are usually composed of only a few types of components in
various combinations.
> A successful, complex system invariably evolves from a simple working system.
40
Software Decomposition
> In the Procedural paradigm, software is decomposed into a hierarchy of
procedures or tasks.
41
Software Decomposition
> In the OO paradigm, software is decomposed into a hierarchy of interacting
components (usually objects).
42
Software Costs
Development:
> OO principles provide a natural technique for modeling business entities and
processes from the early stages of a project.
> OO-modeled business entities and processes are easier to implement in an OO
language.
Maintenance:
> Changeability, flexibility, and adaptability of software is important to keep
software running for a long time.
> OO-modeled business entities and processes can be adapted to new functional
requirements.
43
44
Objects
object = state + behavior
“An object has state, behavior, and identity; the structure and behavior of
similar objects are defined in their common class.”
(Booch Object Solutions page 305)
Objects:
> Have identity
> Are an instance of only one class
> Have attribute values that are unique to that object
> Have methods that are common to the class
45
Objects: Example
46
Classes
A class is a blueprint or prototype from which objects are created. (The Java
Tutorials)
Classes provide:
> The metadata for attributes
> The signature for methods
> The implementation of the methods (usually)
> The constructors to initialize attributes at creation time
47
Classes: Example
48
Abstraction
In OO software, the concept of abstraction enables you to create a simplified, but
relevant view of a real world object within the context of the problem and
solution domains.
> The abstraction object is a representation of the real world object with
irrelevant (within the context of the system) behavior and data removed.
> The abstraction object is a representation of the real world object with
currently irrelevant (within the context of the view) behavior and data hidden.
49
Abstraction: Example
50
Encapsulation
Encapsulation means “to enclose in or as if in a capsule” (Webster New
Collegiate Dictionary)
> Encapsulation is essential to an object. An object is a capsule that holds the
object’s internal state within its boundary.
> In most OO languages, the term encapsulation also includes information hiding,
which can be defined as: “hide implementation details behind a set of non-
private methods”.
51
Encapsulation: Example
52
Encapsulation: Example
53
Inheritance
Inheritance is “a mechanism whereby a class is defined in reference to others,
adding all their features to its own.” (Meyer page 1197)
Features of inheritance:
> Attributes and methods from the superclass are included in the subclass.
> Subclass methods can override superclass methods.
> The following conditions must be true for the inheritance relationship to be
plausible:
– A subclass object is a (is a kind of) the superclass object.
– Inheritance should conform to Liskov’s Substitution Principle (LSP).
54
Inheritance
> Specific OO languages allow either of the following:
– Single inheritance, which allows a class to directly inherit from only one
superclass (for example, Java).
– Multiple inheritance, which allows a class to directly inherit from one or
more superclasses (for example, C++).
55
Inheritance: Example
56
Abstract Classes
A class that contains one or more abstract methods, and therefore can never be
instantiated. (Sun Glossary)
Features of an abstract class:
> Attributes are permitted.
> Methods are permitted and some might be declared abstract.
> Constructors are permitted, but no client may directly instantiate an abstract class.
> Subclasses of abstract classes must provide implementations of all abstract methods;
otherwise, the subclass must also be declared abstract.
> In the UML, a method or a class is denoted as abstract by using italics, or by appending the
method name or class name with {abstract}.
57
58
Interfaces
> Features of Java technology interfaces:
– Attributes are not permitted (except constants).
– Methods are permitted, but they must be abstract.
– Constructors are not permitted.
– Subinterfaces may be defined, forming an inheritance hierarchy of
interfaces.
> A class may implement one or more interfaces.
59
Interfaces: Example
60
Polymorphism
Polymorphism is “a concept in type theory, according to which a name (such as a variable
declaration) may denote objects of many different classes that are related by some common
superclass [type].” (Booch OOAD page 517)
> Aspects of polymorphism:
> A variable can be assigned different types of objects at runtime provided they
are a subtype of the variable’s type.
> Method implementation is determined by the type of object, not the type of
the declaration (dynamic binding).
> Only method signatures defined by the variable type can be called without
casting.
61
Polymorphism: Example
employees = get_project_team()
for (employee in employees)
employee.increase_salary(10)
62
Polymorphism: Example
63
Cohesion
> In software, cohesion refers to how well a given component or method
supports a single purpose.
– Low cohesion occurs when a component is responsible for many unrelated
features.
– High cohesion occurs when a component is responsible for only one set of
related features.
– A component includes one or more classes. Therefore, cohesion applies to a
class, a subsystem, and a system.
– Cohesion also applies to other aspects including methods and packages.
– Components that do everything are often described with the Anti-Pattern
term of Blob components.
64
Cohesion: Example
65
Coupling
Coupling is “the degree to which classes within our system are dependent on each other.”
(Knoernschild page 174)
66
Implementation Inheritance
> Implementation inheritance is inheriting shared attributes and methods from a
superclass
> Advantages:
– Avoids duplication of code that is common to subtypes
– Organizes classes according to inheritance
> Disadvantages:
– Forces subclass to inherit everything from its superclass
– Changes to the superclass might affect the subclass
67
Composition
> Builds complex objects from simpler objects
> Forms a looser coupling than implementation inheritance
class department:
def __init__(self, employee):
self.__employee = employee
@property
def employee(self):
return self.__employee
68
Interface Inheritance
Interface inheritance is the separation of an interface definition from its
implementation:
> Similar to hardware devices that implement a common interface
> Can make a class extensible without being modified
> Java technology-based interfaces (Java interfaces) provide pure interface
inheritance; abstract classes allow a mixture of implementation and interface
inheritance
> This course uses interfaces whenever possible and leaves it to the attendee to
determine whether an abstract class or interface is more appropriate for them
69
class schedulable:
def cancel_activity(self):
pass
def notify_about_activity(self):
pass
class equipment(schedulable):
def cancel_activity(self):
print("equipment::cancel_activity")
def notify_about_activity(self):
print("equipment::notify_about_activity")
70
Class Associations and Object Links
> Dimensions of associations include:
– The roles that each class plays
– The multiplicity of each role
• 1 denotes exactly one
• 1..* denotes one or more
• 0..* or * denotes zero or more
– The direction (or navigability) of the association
– Object links:
• Are instances of the class association
• Are one-to-one relationships
71
72
Delegation
> Many computing problems can be easily solved by delegation to a more
cohesive component (one or more classes) or method.
> Delegation is similar to how we humans behave.
– A manager often delegates tasks to an employee with the appropriate skills.
– You often delegate plumbing problems to a plumber.
– A car delegates accelerate, brake, and steer messages to its subcomponents,
who in turn delegate messages to their subcomponents. This delegation of
messages eventually affects the engine, brakes, and wheel direction
respectively.
> OO paradigm frequently mimics the real world.
73
Delegation
> The ways you delegate in OO paradigm include delegating to:
– A more cohesive linked object
– A collection of cohesive linked objects
– A method in a subclass
– A method in a superclass
– A method in the same class
74
Delegation: Example Problem
75
76
Exploring Object-Oriented Design Principles
> The Gang of Four book outlines three object-oriented design principles:
– Favoring composition
– Programming to an interface
– Designing for change
77
Favoring Composition
“Favor object composition over [implementation] inheritance.” (Gamma, Helm, Johnson,
and Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software)
Reuse functionality through composition instead of implementation inheritance:
> Implementation inheritance is white-box reuse
> Composition is black-box reuse
78
Favoring Composition
79
Favoring Composition
80
Programming to an Interface
“Program to an interface, not an implementation.”
(Gamma, Helm, Johnson, and Vlissides, Design Patterns: Elements of Reusable Object-Oriented
Software)
81
OOP PRINCIPLES
82
THE SINGLE RESPONSIBILITY PRINCIPLE (SRP)
83
> This principle was described in the work of Tom DeMarco [1] and Meilir Page-
Jones [2].
> They called it cohesion, which they defined as the functional relatedness of the
elements of a module.
84
The Single-Responsibility Principle (SRP)
> Why is it so important to separate responsibilities into separate classes?
> Each responsibility is an axis of change.
> When the requirements change, that change will be manifest through a change
in responsibility among the classes.
> If a class assumes more than one responsibility, that class will have more than
one reason to change.
85
86
The Single-Responsibility Principle (SRP)
> Two different applications use the Rectangle class.
> One application does computational geometry. Using Rectangle to help it with
the mathematics of geometric shapes but never drawing the rectangle on the
screen.
> The other application is graphical in nature and may also do some
computational geometry, but it definitely draws the rectangle on the screen.
87
88
The Single-Responsibility Principle (SRP)
> A better design is to separate the two responsibilities into two completely
different classes
89
Defining a Responsibility
> In the context of the SRP, we define a responsibility to be a reason for change.
> If you can think of more than one motive for changing a class, that class has
more than one responsibility.
> This is sometimes difficult to see.
> We are accustomed to thinking of responsibility in groups.
90
Defining a Responsibility: Example
class Modem:
def dial(self, phone_number: str) -> None:
pass
91
93
94
Persistence
> The following shows a common violation of SRP.
> The Employee class contains business rules and persistence control. These two
responsibilities should almost never be mixed.
> Business rules tend to change frequently, and although persistence may not
change as frequently, it changes for completely different reasons.
> Binding business rules to the persistence subsystem is asking for trouble.
95
Conclusion
> The Single-Responsibility Principle is one of the simplest of the principles but
one of the most difficult to get right.
> Conjoining responsibilities is something that we do naturally.
> Finding and separating those responsibilities is much of what software design is
really about.
> Indeed, the rest of the principles we discuss come back to this issue in one way
or another.
96
THE OPEN/CLOSED
PRINCIPLE (OCP)
97
98
The Open/Closed Principle (OCP)
> Software entities (classes, modules, functions, etc.) should be open for
extension but closed for modification.
> When a single change to a program results in a cascade of changes to
dependent modules, the design smells of rigidity.
> OCP advises us to refactor the system so that further changes of that kind will
not cause more modifications.
> If OCP is applied well, further changes of that kind are achieved by adding new
code, not by changing old code that already works.
99
Description of OCP
> They are open for extension. This means that the behavior of the module can
be extended. As the requirements of the application change, we can extend
the module with new behaviors that satisfy those changes. In other words, we
are able to change what the module does.
> They are closed for modification. Extending the behavior of a module does not
result in changes to the source, or binary, code of the module. The binary
executable version of the module remains untouched.
100
Description of OCP
> It would seem that these two attributes are at odds.
> The normal way to extend the behavior of a module is to make changes to the
source code of that module.
> A module that cannot be changed is normally thought to have a fixed behavior.
> How is it possible that the behaviors of a module can be modified without
changing its source code?
> Without changing the module, how can we change what a module does?
101
Description of OCP
> The answer is abstraction.
> In any object-oriented programming language (OOPL), it is possible to create
abstractions that are fixed and yet represent an unbounded group of possible
behaviors.
> The abstractions are abstract base classes, and the unbounded group of
possible behaviors are represented by all the possible derivative classes.
102
Description of OCP
> It is possible for a module to manipulate an abstraction.
– Such a module can be closed for modification, since it depends on an
abstraction that is fixed.
– Yet the behavior of that module can be extended by creating new
derivatives of the abstraction.
103
Description of OCP
> Both the Client and Server classes are concrete.
> The Client class uses the Server class.
> If we want for a Client object to use a different server object, Client class
must be changed to name new server class.
Client Server
104
Description of OCP
> If we want Client objects to use a different server class, a new derivative of the
ClientInterface class can be created.
> The Client class can remain unchanged.
«interface»
Client IClient
Server
105
Description of OCP
> You may wonder why I named IClient the way I did.
> Why didn't I call it AbstractServer instead?
> Abstract classes are more closely associated to their clients than to the classes
that implement them.
106
THE LISKOV SUBSTITUTION PRINCIPLE (LSP)
107
108
The Liskov Substitution Principle
> New classes should be logical, consistent extensions of their superclasses, but
what does it mean to be logical and consistent?
> A Java compiler will ensure a certain level of consistency, but many principles
of consistency will elude a compiler.
> One principle you should consider in your designs is the Liskov Substitution
Principle (LSP).
> This principle, documented in Liskov (1987), can be paraphrased: An instance
of a class should function as an instance of its superclass.
109
110
LSP Example
> Consider the following Rectangle class:
class Rectangle:
def __init__(self, width: float, height: float):
self.__width = width
self.__height = height
@property
def width(self) -> float: @property
return self.__width def height(self) -> float:
return self.__height
@width.setter
def width(self, value) -> None: @height.setter
self.__width = value def height(self, value) -> None:
self.__height = value
111
LSP Example
> Here's the Square class:
class Square(Rectangle):
def __init__(self, edge: float):
super().__init__(edge, edge)
@property
def width(self) -> float:
return self.__width
@width.setter
def width(self, value) -> None:
self.__width = value
self.__height = value @height.setter
def height(self, value) -> None:
@property self.__width = value
def height(self) -> float: self.__height = value
return self.__height
112
LSP Example
> Now, had about a Square class? Clearly, a square is a rectangle, so the Square
class should be derived from the Rectangle class, right? Let's see!
> Observations:
– A square does not need both a width and a height as attributes, but it will
inherit them from Rectangle anyway. So, each Square object wastes a little
memory, but this is not a major concern.
– The inherited setWidth() and setHeight() methods are not really
appropriate for a Square, since the width and height of a square are
identical. So we'll need to override setWidth() and setHeight().
113
LSP Example
> Everything looks good. But check this out!
public class TestRectangle {
public static void testLSP(Rectangle r){
r.setWidth(4.0);
r.setHeight(5.0);
if (r.area() == 20.0)
System.out.println("Looking good!\n");
else
System.out.println("What kind of “ +
"rectangle is this??\n");
}
114
LSP Example
def test_lsp(rectangle: Rectangle) -> None:
rectangle.width = 4.0
rectangle.height = 5.0
if rectangle.area() == 20.0:
print("Looking good!\n");
else:
print("What kind of rectangle is this?\n")
r = Rectangle(4, 5)
test_lsp(r)
r = Square(10)
test_lsp(r)
115
LSP Example
> A mathematical square might be a rectangle, but a Square object is not a
Rectangle object
> A Square object is not consistent with the behavior of a Rectangle object!
> Behaviorally, a Square is not a Rectangle!
> A Square object is not polymorphic with a Rectangle object.
116
LSP Example
class Shape:
def area(self) -> float:
pass
117
LSP Example
> class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.__width = width
self.__height = height
@property
def width(self) -> float: @property
return self.__width def height(self) -> float:
return self.__height
@width.setter
def width(self, value) -> None: @height.setter
self.__width = value def height(self, value) -> None:
self.__height = value
118
LSP Example
class Square(Shape):
def __init__(self, edge: float):
self.__edge = edge
@property
def edge(self) -> float:
return self.__edge
@edge.setter
def edge(self, value) -> None:
self.__edge = value
119
120
Liskov Substitution Principle
> If the subtype has more constraints than the base type, there would be uses
that would be valid for the base type, but that would violate one of the extra
constraints of the subtype and thus violate the LSP!
> The guarantee of the LSP is that a subclass can always be used wherever its
base class is used!
121
PRINCIPLE #4
THE INTERFACE SEGREGATION PRINCIPLE (ISP)
Clients should not be forced to depend on methods they do not use.
122
Fat Interfaces
> “Fat" interfaces
– Classes whose interfaces are not cohesive have "fat" interfaces.
– The interfaces of the class can be broken up into groups of methods.
– Each group serves a different set of clients. Thus, some clients use one group
of methods, and other clients use the other groups.
> It suggests
– Clients should not know about them as a single class.
– Clients should know about abstract base classes that have cohesive
interfaces.
123
Interface Pollution
> Clients should not be forced to depend on methods they do not use.
124
class TimerClient:
def timeOut(self, timeout_id: int) -> None:
pass
class Timer:
def register(self, timeout: int, timeout_id: int, client: TimerClient):
# provide an implementation
pass
125
126
Separation Through Multiple Inheritance
127
128
ATM transaction hierarchy
129
130
DEPENDENCY INVERSION PRINCIPLE (DIP)
131
132
Dependency Inversion Principle
> An abstraction can be a Java technology interface:
133