⚙️OOP-2

OBJECT ORIENTED PROGRAMMING-II

Object Oriented Programming-II

Encapsulation

Encapsulation is one of the fundamental concepts in object-oriented programming (OOP). It describes the idea of wrapping data and the methods that work on data within one unit. This puts restrictions on accessing variables and methods directly and can prevent the accidental modification of data. To prevent accidental change, an object’s variable can only be changed by an object’s method. Those types of variables are known as private variable.

The following defines the Counter class:

class Counter:
    def __init__(self):
        self.current = 0

    def increment(self):
        self.current += 1

    def value(self):
        return self.current

    def reset(self):
        self.current = 0

The Counter class has one attribute called current which defaults to zero. And it has three methods:

  • increment() increases the value of the current attribute by one.

  • value() returns the current value of the current attribute

  • reset() sets the value of the current attribute to zero.

The following creates a new instance of the Counter class and calls the increment() method three times before showing the current value of the counter to the screen:

counter = Counter()

counter.increment()
counter.increment()
counter.increment()

print(counter.value())

It works perfectly fine but has one issue.

From the outside of the Counter class, you still can access the current attribute and change it to whatever you want. For example:

counter = Counter()

counter.increment()
counter.increment()
counter.current = -999

print(counter.value())

In this example, we create an instance of the Counter class, call the increment() method twice and set the value of the current attribute to an invalid value -999.

So how do you prevent the current attribute from modifying outside of the Counter class?

That’s why private attributes come into play.

Private attributes

Private attributes can be only accessible from the methods of the class. In other words, they cannot be accessible from outside of the class.

To make an attribute private, you prefix it with a double underscore (__). The following redefines the Counter class with the current as a private attribute:

class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

The following creates a new instance of the Counter class and access the __current attribute:

counter = Counter()
print(counter.__current)

Python issues the following error:

AttributeError: 'Counter' object has no attribute '__current'

As you can see, the Counter class now can protect its internal state from the outside.

Polymorphism

Polymorphism is an ability (in OOP) to use a common interface for multiple forms (data types).

Suppose, we need to color a shape, there are multiple shape options (rectangle, square, circle). However we could use the same method to color any shape. This concept is called Polymorphism.

class Parrot:

    def fly(self):
        print("Parrot can fly")
    
    def swim(self):
        print("Parrot can't swim")

class Penguin:

    def fly(self):
        print("Penguin can't fly")
    
    def swim(self):
        print("Penguin can swim")

# common interface
def flying_test(bird):
    bird.fly()

#instantiate objects
blu = Parrot()
peggy = Penguin()

# passing the object
flying_test(blu)
flying_test(peggy)

In the above program, we defined two classes Parrot and Penguin. Each of them have a common fly() method. However, their functions are different.

To use polymorphism, we created a common interface i.e flying_test() function that takes any object and calls the object's fly() method. Thus, when we passed the blu and peggy objects in the flying_test() function, it ran effectively.

Python staticmethod()

A @staticmethod is a method that knows nothing about the class or instance it was called on unless explicitly given. It just gets the arguments that were passed, no implicit first argument and It’s definition is immutable via inheritance.

In simpler words a @staticmethod is nothing more than a regular function defined inside a class that doesn’t have access to the instance therefore It is callable without instantiating the class.

1 class ClassName:
2     @staticmethod
3     def method_name(arg1, arg2, ...): ...

We use the @staticmethod decorator for defining a static method in Python, here you can observe that the static method is not taking self as an argument for the method.

Now let’s look at an example.

1 class Myclass():
2     @staticmethod
3     def staticmethod():
4         print('static method called')

As we discussed we can access the static method of a class without creating an object.

Myclass.staticmethod()

Although calling the method from a class instance is also possible.

my_obj = Myclass()
my_obj.staticmethod()

Great, but when are static methods useful?

The static method helps in achieving encapsulation in Python class since it is not aware of the state of the current instance. Also, static methods make code more readable and reusable and more convenient to import versus module-level functions since each method does not have to be specially imported.

1 class Person():
2     @staticmethod
3     def is_adult(age):
4         if age > 18:
5             return True
6         else:
7             return False

In the above example, we can check if the person is an adult with or without initiating the class.

Person.is_adult(23)

Python classmethod()

A @classmethod is a method that receives the class as the implicit first argument, just like an instance method receives the instance. This means you can use the class and its properties inside that method rather than a particular instance.

So @classmethod is basically a method of a class having access to every attribute of the class it was called on. Therefore a class method is a method that is bound to the class and not the object of the class.

Syntax:

class Class:
    @classmethod
    def method(cls, arg1, arg2, ...): ...

The @classmethod decorator is used for creating a class methods and cls should be the first argument of every class method.

class MyClass:
    @classmethod
    def classmethod(cls):
        print('Class method called')

@classmethod functions are also callable without instantiating the class, but its definition follows Subclass, not Parent class, via inheritance.

MyClass.classmethod()

@classmethod are for when you need to have methods that aren’t specific to any particular instance, but still, involve the class in some way. The most interesting thing about them is that they can be overridden by subclasses.

So If you want to access a property of a class as a whole, and not the property of a specific instance of that class, use a class method.

class MyClass():

    TOTAL_OBJECTS=0

    def __init__ (self):
        MyClass.TOTAL_OBJECTS = MyClass.TOTAL_OBJECTS+1

    @classmethod
    def total_objects(cls):
        print("Total objects: ",cls.TOTAL_OBJECTS)

 # Creating objects
my_obj1 = MyClass()
my_obj2 = MyClass()
my_obj3 = MyClass()

# Calling class method
MyClass.total_objects()

Now if we inherit this class into a child class and declare the TOTAL_OBJECTS variable there and call the class method from child class it will return the total object count for the child class.

class MyClass():

    TOTAL_OBJECTS=0

    def __init__ (self):
        MyClass.TOTAL_OBJECTS = MyClass.TOTAL_OBJECTS+1

    @classmethod
    def total_objects(cls):
        print("Total objects: ",cls.TOTAL_OBJECTS)

# Creating objects of parent class
my_obj1 = MyClass()
my_obj2 = MyClass()


# Creating a child class
class ChildClass(MyClass):
    TOTAL_OBJECTS=0
    pass

ChildClass.total_objects()

Wrapping it up

@classmethod is used in a superclass to define how that method should behave when it’s called by different child classes. Whereas a @staticmethod is used when we want to return the same thing regardless of the child class that we are calling.

Also, keep a note that calling a @classmethod involves an additional memory allocation that calling a @staticmethod or regular function does not.

Python’s @property Decorator

Python provides a built-in @property decorator which makes usage of getter and setters much easier in Object-Oriented Programming.

Properties are useful because they allow us to handle both setting and getting values in a programmatic way but still allow attributes to be accessed as attributes.

Let’s look at one example.

class Circle():
    def __init__ (self, radius):
        self.diameter = 2*radius

    def circumference(self):
        return 3.14*self.diameter

    @property
    def radius(self):
        return self.diameter / 2

    @radius.setter
    def radius(self, radius):
        self.diameter = 2 * radius

In Python, @property is a built-in decorator that creates and returns a property object. The @property decorator is internally taking the bounded method as an argument and returns a descriptor object. That descriptor object then gets the same name of the old method therefore the setter method is bound to that method i.e. @radius.setter the method getter is referring too.

Now let’s create an object and get its circumference

c = Circle(radius=2)
c.circumference()

Next, let’s use the radius setter method.

c.radius = 3
c.circumference()

Properties solve several problems. The main one is that they allow you to substitute a method call for attribute access without changing the public API. That is important if you’re dealing with large software projects where you can’t break backward compatibility. You can easily modify your class to add getters and setters for the data without changing the interface, so you don’t have to find everywhere in your code where that data is accessed and change that too.

UML Diagrams

What is Class Diagram?

A Class Diagram in Software engineering is a static structure that gives an overview of a software system by displaying classes, attributes, operations, and their relationships between each other. This Diagram includes the class name, attributes, and operation in separate designated compartments. Class Diagram helps construct the code for the software application development.

Class Diagram defines the types of objects in the system and the different types of relationships that exist among them. It gives a high-level view of an application. This modeling method can run with almost all Object-Oriented Methods. A class can refer to another class. A class can have its objects or may inherit from other classes.

Benefits of Class Diagram

  • Class Diagram Illustrates data models for even very complex information systems

  • It provides an overview of how the application is structured before studying the actual code. This can easily reduce the maintenance time

  • It helps for better understanding of general schematics of an application.

  • Allows drawing detailed charts which highlights code required to be programmed

  • Helpful for developers and other stakeholders.

UML Class Notation

A class represent a concept which encapsulates state (attributes) and behavior (operations). Each attribute has a type. Each operation has a signature. The class name is the only mandatory information.

Essential elements of UML class diagram are:

  1. Class Name

  2. Attributes

  3. Operations

Class Name:

The name of the class is only needed in the graphical representation of the class. It appears in the topmost compartment. A class is the blueprint of an object which can share the same relationships, attributes, operations, & semantics. The class is rendered as a rectangle, including its name, attributes, and operations in sperate compartments.

Following rules must be taken care of while representing a class:

  1. A class name should always start with a capital letter.

  2. A class name should always be in the center of the first compartment.

  3. A class name should always be written in bold format.

  4. UML abstract class name should be written in italics format.

Class Attributes:

  • Attributes are shown in the second partition.

  • The attribute type is shown after the colon.

  • The attributes are generally written along with the visibility factor.

  • Public, private, protected and package are the four visibilities which are denoted by +, -, #, or ~ signs respectively.

  • Visibility describes the accessibility of an attribute of a class.

  • Attributes must have a meaningful name that describes the use of it in a class.

  • Attributes map onto member variables (data members) in code.

Class Operations (Methods):

  • Operations are shown in the third partition. They are services the class provides.

  • The return type of a method is shown after the colon at the end of the method signature.

  • The return type of method parameters are shown after the colon following the parameter name. Operations map onto class methods in code

Class Visibility

The +, - and # symbols before an attribute and operation name in a class denote the visibility of the attribute and operation.

  • + denotes public attributes or operations

  • - denotes private attributes or operations

  • # denotes protected attributes or operations

Perspectives of Class Diagram

The choice of perspective depends on how far along you are in the development process. During the formulation of a domain model, for example, you would seldom move past the conceptual perspective. Analysis models will typically feature a mix of conceptual and specification perspectives. Design model development will typically start with heavy emphasis on the specification perspective, and evolve into the implementation perspective.

A diagram can be interpreted from various perspectives:

  • Conceptual: represents the concepts in the domain

  • Specification: focus is on the interfaces of Abstract Data Type (ADTs) in the software

  • Implementation: describes how classes will implement their interfaces

The perspective affects the amount of detail to be supplied and the kinds of relationships worth presenting. As we mentioned above, the class name is the only mandatory information.

Relationships between classes

UML is not just about pretty pictures. If used correctly, UML precisely conveys how code should be implemented from diagrams. If precisely interpreted, the implemented code will correctly reflect the intent of the designer. Can you describe what each of the relationships mean relative to your target programming language shown in the Figure below?

If you can't yet recognize them, no problem this section is meant to help you to understand UML class relationships. A class may be involved in one or more relationships with other classes. A relationship can be one of the following types:

Inheritance (or Generalization):

A generalization is a taxonomic relationship between a more general classifier and a more specific classifier. Each instance of the specific classifier is also an indirect instance of the general classifier. Thus, the specific classifier inherits the features of the more general classifier.

  • Represents an "is-a" relationship.

  • An abstract class name is shown in italics.

  • SubClass1 and SubClass2 are specializations of SuperClass.

The figure below shows an example of inheritance hierarchy. SubClass1 and SubClass2 are derived from SuperClass. The relationship is displayed as a solid line with a hollow arrowhead that points from the child element to the parent element.

Inheritance Example - Shapes

The figure below shows an inheritance example with two styles. Although the connectors are drawn differently, they are semantically equivalent.

Simple Association

  • A structural link between two peer classes.

  • There is an association between Class1 and Class2

The figure below shows an example of simple association. There is an association that connects the class Department and class College. The relationship is displayed as a solid line connecting the two classes.

Cardinality

Cardinality is expressed in terms of:

  • one to one

  • one to many

  • many to many

For example, multiple patients are admitted to one hospital.

Aggregation

An aggregation is a subset of association, which represents has a relationship. It is more specific then association. It defines a part-whole or part-of relationship. In this kind of relationship, the child class can exist independently of its parent class.

The figure below shows an example of aggregation. The relationship is displayed as a solid line with a unfilled diamond at the association end, which is connected to the class that represents the aggregate.

The company encompasses a number of employees, and even if one employee resigns, the company still exists.

Composition

The composition is a subset of aggregation. It portrays the dependency between the parent and its child, which means if one part is deleted, then the other part also gets discarded. It represents a whole-part relationship.

The figure below shows an example of composition. The relationship is displayed as a solid line with a filled diamond at the association end, which is connected to the class that represents the whole or composite.

A contact book consists of multiple contacts, and if you delete the contact book, all the contacts will be lost.

Dependency

An object of one class might use an object of another class in the code of a method. If the object is not stored in any field, then this is modeled as a dependency relationship.

  • A special type of association.

  • A dependency is a semantic relationship between two or more classes where a change in one class cause changes in another class.

The figure below shows an example of dependency. The relationship is displayed as a dashed line with an open arrow.

In the following example, Student_Name is dependent on the Student_Id.

The figure below shows another example of dependency. The Person class might have a hasRead method with a Book parameter that returns true if the person has read the book (perhaps by checking some database).

Class Diagram Example: Order System

Example of UML Class Diagram

Creating a class diagram is a straightforward process. It does not involve many technicalities. Here, is an example:

ATMs system is very simple as customers need to press some buttons to receive cash. However, there are multiple security layers that any ATM system needs to pass. This helps to prevent fraud and provide cash or need details to banking customers.

Below given is a UML Class Diagram example:

Conclusion

  • UML is the standard language for specifying, designing, and visualizing the artifacts of software systems

  • A class is a blueprint for an object

  • A class diagram describes the types of objects in the system and the different kinds of relationships which exist among them

  • It allows analysis and design of the static view of a software application

  • Class diagrams are most important UML diagrams used for software application development

  • Essential elements of UML class diagram are 1) Class 2) Attributes 3) Relationships

  • Class Diagram provides an overview of how the application is structured before studying the actual code. It certainly reduces the maintenance time

  • The class diagram is useful to map object-oriented programming languages like Java, C++, Ruby, Python, etc.

UML Use Case Diagram

What is the Use Case Diagram?

Use Case Diagram captures the system’s functionality and requirements by using actors and use cases. Use Cases model the services, tasks, function that a system needs to perform. Use cases represent high-level functionalities and how a user will handle the system. Use-cases are the core concepts of Unified Modelling language modeling.

Why Use-Case diagram?

A Use Case consists of use cases, persons, or various things that are invoking the features called as actors and the elements that are responsible for implementing the use cases. Use case diagrams capture the dynamic behaviour of a live system. It models how an external entity interacts with the system to make it work. Use case diagrams are responsible for visualizing the external things that interact with the part of the system.

Use-case diagram notations

Following are the common notations used in a use case diagram:

Use-case:

Use cases are used to represent high-level functionalities and how the user will handle the system. A use case represents a distinct functionality of a system, a component, a package, or a class. It is denoted by an oval shape with the name of a use case written inside the oval shape. The notation of a use case in UML is given below:

Actor:

It is used inside use case diagrams. The actor is an entity that interacts with the system. A user is the best example of an actor. An actor is an entity that initiates the use case from outside the scope of a use case. It can be any element that can trigger an interaction with the use case. One actor can be associated with multiple use cases in the system. The actor notation in UML is given below.

How to draw a use-case diagram?

To draw a use case diagram in UML first one need to analyse the entire system carefully. You have to find out every single function that is provided by the system. After all the functionalities of a system are found out, then these functionalities are converted into various use cases which will be used in the use case diagram.

A use case is nothing but a core functionality of any working system. After organizing the use cases, we have to enlist the various actors or things that are going to interact with the system. These actors are responsible for invoking the functionality of a system. Actors can be a person or a thing. It can also be a private entity of a system. These actors must be relevant to the functionality or a system they are interacting with.

After the actors and use cases are enlisted, then you have to explore the relationship of a particular actor with the use case or a system. One must identify the total number of ways an actor could interact with the system. A single actor can interact with multiple use cases at the same time, or it can interact with numerous use cases simultaneously.

Following rules must be followed while drawing use-case for any system:

  1. The name of an actor or a use case must be meaningful and relevant to the system.

  2. Interaction of an actor with the use case must be defined clearly and in an understandable way.

  3. Annotations must be used wherever they are required.

  4. If a use case or an actor has multiple relationships, then only significant interactions must be displayed.

Tips for drawing a use-case diagram

  1. A use case diagram should be as simple as possible.

  2. A use case diagram should be complete.

  3. A use case diagram should represent all interactions with the use case.

  4. If there are too many use cases or actors, then only the essential use cases should be represented.

  5. A use case diagram should describe at least a single module of a system.

  6. If the use case diagram is large, then it should be generalized.

An example of a use-case diagram

Following use case diagram represents the working of the student management system: END OF THE LECTURE

In the above use case diagram, there are two actors named student and a teacher. There are a total of five use cases that represent the specific functionality of a student management system. Each actor interacts with a particular use case. A student actor can check attendance, timetable as well as test marks on the application or a system. This actor can perform only these interactions with the system even though other use cases are remaining in the system.

It is not necessary that each actor should interact with all the use cases, but it can happen.

The second actor named teacher can interact with all the functionalities or use cases of the system. This actor can also update the attendance of a student and marks of the student. These interactions of both student and a teacher actor together sums up the entire student management application.

When to use a use-case diagram?

A use case is a unique functionality of a system which is accomplished by a user. A purpose of use case diagram is to capture core functionalities of a system and visualize the interactions of various things called as actors with the use case. This is the general use of a use case diagram.

The use case diagrams represent the core parts of a system and the workflow between them. In use case, implementation details are hidden from the external use only the event flow is represented.

With the help of use case diagrams, we can find out pre and post conditions after the interaction with the actor. These conditions can be determined using various test cases.

In general use case diagrams are used for:

  1. Analyzing the requirements of a system

  2. High-level visual software designing

  3. Capturing the functionalities of a system

  4. Modeling the basic idea behind the system

  5. Forward and reverse engineering of a system using various test cases.

Use cases are intended to convey desired functionality so the exact scope of a use case may vary according to the system and the purpose of creating UML model.

Example of a Use Case Diagram

A use case diagram depicting the Online Shopping website is given below.

Here the Web Customer actor makes use of any online shopping website to purchase online. The top-level uses are as follows; View Items, Make Purchase, Checkout, Client Register. The View Items use case is utilized by the customer who searches and view products. The Client Register use case allows the customer to register itself with the website for availing gift vouchers, coupons, or getting a private sale invitation. It is to be noted that the Checkout is an included use case, which is part of Making Purchase, and it is not available by itself.

The View Items is further extended by several use cases such as; Search Items, Browse Items, View Recommended Items, Add to Shopping Cart, Add to Wish list. All of these extended use cases provide some functions to customers, which allows them to search for an item. The View Items is further extended by several use cases such as; Search Items, Browse Items, View Recommended Items, Add to Shopping Cart, Add to Wish list. All of these extended use cases provide some functions to customers, which allows them to search for an item.

Both View Recommended Item and Add to Wish List include the Customer Authentication use case, as they necessitate authenticated customers, and simultaneously item can be added to the shopping cart without any user authentication.

Similarly, the Checkout use case also includes the following use cases, as shown below. It requires an authenticated Web Customer, which can be done by login page, user authentication cookie ("Remember me"), or Single Sign-On (SSO). SSO needs an external identity provider's participation, while Web site authentication service is utilized in all these use cases.

The Checkout use case involves Payment use case that can be done either by the credit card and external credit payment services or with PayPal.

Summary

  • Use case diagrams are a way to capture the system’s functionality and requirements in UML diagrams.

  • It captures the dynamic behavior of a live system.

  • A use case diagram consists of a use case and an actor.

  • A use case represents a distinct functionality of a system, a component, a package, or a class.

  • An actor is an entity that initiates the use case from outside the scope of a use case.

  • The name of an actor or a use case must be meaningful and relevant to the system.

  • A purpose of use case diagram is to capture the core functionalities of a system.

END OF THE LECTURE

Last updated

Change request #338: