Wednesday, December 6, 2023

Why I taught my son Design Pattern even before Data Structure...



Studying design patterns helps a software developer get the big picture - from a designer's perspective. Knowing the common design patterns enables us to understand how different parts of the software are related to each other. Not only this, but knowledge of design patterns helps to communicate with other developers in a more object-oriented way.

Let me give you an example.

You know callback mechanism, observer pattern, and event listener pattern - all do kind of the same work - notify some objects when a specific event occurs. However, without the knowledge of design patterns, we will simply try to understand this phenomenon from just a programmer's point of view - and definitely, we will miss the big picture behind writing such kinds of object-oriented code.

I remember, when I studied the command routing architecture of Visual C++/MFC source code, I tried to map it with the Gang of Four design patterns and found out that this architecture uses two common design patterns at the same time - Command pattern and Chain of responsibility pattern.

Studying design patterns helps to decipher object-oriented code more like a professional - and not like a novice programmer. 

It helps to figure out the source code not only from what and how's point of view, but also from Why's point of view. We can explain why a piece of code has been or should be written in a particular way.

Understanding the Why's is very essential for a software developer.

Let me tell you about my journey in NOKIA India in 2007 using Symbian S60 C++ framework.

There is a concept in Symbian called a two-phase constructor. I asked people about the Why's point of view. Nobody gave me the answer - everybody said this is the norm in Symbian. While breaking my head about this "why", I went to Japan and then realized the reason for such a two-phase constructor - to avoid the exception during constructor in case of low memory. Because in the earlier days of mobile phones, there was limited memory and moreover there were no template concepts in C++. Hence there was no smart pointer. This led me to study Boost pointer in Japan in 2008 and voila, in 2009 Boost library became a part of the standard C++ library.

In concisely, to get the big picture of any object-oriented code structure, it's important to know Design Patterns. It clarifies many questions - particularly why a piece of code should be written in a specific manner.

Here's the evolutionary journey of Ridit, my son and a young Computer Scientist of Bharat - vis-a-vis Design Pattern...

My bragging right - as a Guru of my son...

State Pattern in Java : 8 yrs old

State pattern in C++ : 11 yrs old

State pattern in Python : 12 yrs old

Thursday, November 23, 2023

A baby step in the wonderland of Quantum Computing...

I am of the opinion that there is no age limit for trying out new things in life.

I consider myself a perpetual student.

Today will be a memorable day for me.

I have started my journey into the world of Quantum Computing.

From almost no knowledge in college (even didn't know how to start the Basic development environment) to taking concrete steps to pick up Quantum Computing - it's a checkered journey - a lot of midnight oil is burnt - a lot of frustration, many times it became unbearable, traveled many places - but one thing always drove me - the intrinsic motivation - never did anything just for monetary gain - remained a perpetual student. I started my software journey when there was no Google. it was naturally challenging. but worth the effort...

So, here we go - my first coding in the area of Quantum Programming.

#Python libraries required for various operations
import numpy as np

#Qiskit packages used for building a quantum circuit
from qiskit import QuantumRegister, ClassicalRegister
from qiskit import QuantumCircuit

#Qiskit packages used to execute and simulate the quantum circuit
from qiskit import execute, Aer

#Qiskit packages used to visualize and analyze results
from qiskit.visualization import plot_histogram

#Create quantum register to store qubit
qreg_q = QuantumRegister(1, 'q')

#Create classical register to store the results
creg_c = ClassicalRegister(1, 'c')

#Initialize quantum circuit
circuit = QuantumCircuit(qreg_q, creg_c)

#Initialize all qubits to |0>
circuit.reset(qreg_q)

#Apply the Hadamard gate on the qubit
circuit.h(qreg_q)

#Apply measurement
circuit.measure(qreg_q, creg_c)

#Visualize the constructed circuit
circuit.draw()

# Use Aer's qasm_simulator
simulator = Aer.get_backend('qasm_simulator')

# Execute the circuit on the qasm simulator
job = execute(circuit, simulator, shots=1000)

# Grab results from the job
result = job.result()

# Returns counts
counts = result.get_counts(circuit)
print("\n Output counts:",counts)

# Plot a histogram
plot_histogram(counts)


Here is the output

Output counts: {'1': 464, '0': 536}


And here goes another simple program of a basic entangler.

Enjoy...

#Python libraries required for various operations
import numpy as np

#Qiskit packages used for building a quantum circuit
from qiskit import QuantumRegister, ClassicalRegister
from qiskit import QuantumCircuit

#Qiskit packages used to execute and simulate the quantum circuit
from qiskit import execute, Aer


#Qiskit packages used to visualize and analyze results
from qiskit.visualization import plot_histogram

qreg_q = QuantumRegister(2, 'q')
creg_c = ClassicalRegister(2, 'c')
circuit = QuantumCircuit(qreg_q, creg_c)

circuit.reset(qreg_q[0])
circuit.reset(qreg_q[1])
circuit.h(qreg_q[0])
circuit.cx(qreg_q[0], qreg_q[1])
circuit.measure(qreg_q[0], creg_c[0])
circuit.measure(qreg_q[1], creg_c[1])

#Visualize the constructed circuit
circuit.draw()

# Use Aer's qasm_simulator
simulator = Aer.get_backend('qasm_simulator')

# Execute the circuit on the qasm simulator
job = execute(circuit, simulator, shots=1000)

# Grab results from the job
result = job.result()

# Returns counts
counts = result.get_counts(circuit)
print("\n Output counts:",counts)

# Plot a histogram
plot_histogram(counts)

Here goes the output of the above piece of code

Output counts: {'00': 489, '11': 511}

To start something absolutely new is challenging yet satisfying. I am always motivated by intrinsic motivation. Hence the joy of learning is still there in me, a perpetual student…

Thursday, November 16, 2023

Engineers of Bharat - wakeup - know WhoWeAre - part II

 Here's the clarion call to all of the engineers of Bharat - embrace #Sanskrit and go back to your roots. Know your real worth.

Till to date, scientists are baffled at how the Tithis are so accurately calculated in ancient Bharat.

Read the following article.

Our Vedas were written more than 15000 years ago.

Isn't it amazing?

We were invaded by Muslims and then the British - but our only defeat has become true when an inferiority complex was injected into us.

Come ON... the Humans of Bharat...

please ... 

wake up and reclaim who you are...

Read... Read...



And see how modern scientists are struggling to calculate the Tithis given in Panjika of Bharat.
 


Through this write-up, I am requesting the Government of Bharat to embrace Sanskrit and our ancient knowledge and become a real Vishwaguru - the original, pure, unpolluted.

Reclaiming WhoWeAre...

So, the Humans of Bharat...

please wake up...

Read.... Read...

Saturday, September 2, 2023

Iterator Design Pattern in Python...

Iterator design pattern is a behavioral design pattern that lets you access the element of a complex data structure - a collection class - without the knowledge of the internal structure of the elements it is accessing.

To create an iterator in Python, there are two abstract classes from the built-in `collections` module - Iterable, and Iterator. We need to implement the

`__iter__()` method in the iterated object (collection), and the `__next__ ()` method in the iterator.

The concrete class that implements the Iterator class provides various means of different ways of iteration through the collection class.

In our example, AlphabeticalOrderIterator is such a class that has provided forward and reverse ways of iteration. In this example, the WordsCollection class represents a collection of words and implements the Iterable interface.

The source code is as follows:

from collections.abc import Iterator, Iterable
from typing import Any, List

class WordsCollection(Iterable):
def __init__(self, collection: List[Any]=[]):
self._collection = collection

def __iter__(self):
return AlphabeticalOrderIterator(self._collection)

def get_reverse_iterator(self):
return AlphabeticalOrderIterator(self._collection, True)

def add_item(self, item:Any):
self._collection.append(item)

class AlphabeticalOrderIterator(Iterator):
_position = None
_reverse = False

def __init__(self, collection : WordsCollection, reverse: bool = False):
self._collection = collection
self._reverse = reverse
self._position = -1 if self._reverse else 0

def __next__(self):
try:
value = self._collection[self._position]
self._position += -1 if self._reverse else 1
except IndexError:
raise StopIteration()

return value


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
wordsCollection = WordsCollection()
wordsCollection.add_item("Som")
wordsCollection.add_item("Reema")
wordsCollection.add_item("Ridit")

print("Forward traversal:")
print("\n".join(wordsCollection))
print("")

print("Reverse traversal:")
print("\n".join(wordsCollection.get_reverse_iterator()), end="")

If we run the above program the output will be as follows:

Forward traversal:

Som

Reema

Ridit


Reverse traversal:

Ridit

Reema

Som

 

Friday, September 1, 2023

Prototype Design Pattern in Python...

The prototype design pattern is a creational pattern.

If the creation of an object is a very costly affair and we already have a similar kind of object, instead of creating it each time we need it, we use the clone of the object that is already there.

Suppose, there is a large object with many attributes whose data we read from a database. We need to modify that data multiple times in our program. So instead of creating the object each time by reading from the database, we tend to keep a prototype object - we clone it, and then work on it.

In Python, there is a module called copy which has two methods - copy() and deepcopy(). The first one is for the shallow copy and the second one is for the deepcopy.

Here is the source code of an example of the Prototype design pattern.

from abc import ABC, abstractmethod
import copy

class Person(ABC):
def __init__(self, name):
self._name = name
def set_name(self, name):
self._name = name
def get_name(self):
return self._name
@abstractmethod
def clone(self):
pass
@abstractmethod
def display(self):
pass

class Teacher(Person):
def __init__(self, name, course):
super().__init__(name)
self._course = course
def set_course(self, course):
self._course = course
def get_course(self):
return self._course
def display(self):
print("\nTeacher's name : ", self._name, "\n")
print("\nHe teaches : ", self.get_course())

def clone(self):
return copy.deepcopy(self)

class Student(Person):
def __init__(self, name, teacher):
super().__init__(name)
self._teacher = teacher

def display(self):
print("\n Student's name : ", self.get_name())
print("\n Taught by : ", self._teacher.get_name())
print("\n Enrolled in the subject : ", self._teacher.get_course())

def clone(self):
return copy.deepcopy(self)



if __name__ == '__main__':
teacher = Teacher('Som', "Python Design Patttern")
teacherClone1 = teacher.clone()

student = Student ("Ridit", teacherClone1)

studentClone1 = student.clone()

teacherClone1.set_course("DSA")

teacherClone1.display()

studentClone1.display()



If we run the above piece of code the result will be as follows:

Teacher's name :  Som 

He teaches :  Python Design Patttern

Teacher's name :  Som 

He teaches :  DSA

Student's name :  Ridit

Taught by :  Som

Enrolled in the subject :   Python Design Patttern


As you can see, we have used deep copy here.

Sunday, August 27, 2023

Decorator Design Pattern in Python

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class.

What problems can it solve?

- Responsibilities should be added to (and removed from) an object dynamically at run-time

- A flexible alternative to subclassing for extending functionality should be provided.

The UML diagram of the example is given below:



When using subclassing, different subclasses extend a class in different ways. But an extension is bound to the class at compile-time and can't be changed at run-time.

The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class.

This is achieved by designing a new Decorator class that wraps the original class. This wrapping could be achieved by the following sequence of steps:

Subclass the original Component class into a Decorator class (see UML diagram);

- In the Decorator class (SpecialistTeacher), add a Component reference as an attribute;

- In the Decorator class, pass a Component to the Decorator constructor to initialize the Component attribute;

- In the Decorator class, forward all Component methods to the Component pointer; and

- In the ConcreteDecorator class (specialistMathTeacher, specialistChemistryTeacher, etc), override any Component method(s) whose behavior needs to be modified.

This pattern is designed so that multiple decorators can be stacked on top of each other, each time adding a new functionality to the overridden method(s).

Note that decorators and the original class object share a common set of features. In the UML diagram, the doWork() and calculateSalary() methods were available in both the decorated and undecorated versions.

Here is the source code of the Decorator Design Pattern in Python:

from abc import ABC, abstractmethod

class Teacher(ABC):
@abstractmethod
def calculateSalary(self):
pass
def doWork(self):
pass

class BasicTeacher(Teacher):
def __init__(self, baseSalaryForATeacher):
self.baseSalaryForTeacher = baseSalaryForATeacher

def calculateSalary(self):
return self.baseSalaryForTeacher
def doWork(self):
pass

##Decorator
class SpecialistTeacher(Teacher):
def __init__(self, teacher):
self.teacher = teacher

def calculateSalary(self):
self.specialistTeacherBaseSalary = self.teacher.calculateSalary()
return self.specialistTeacherBaseSalary
def doWork(self):
super().doWork()
self.teacher.doWork()

class SpecialistPhysicsTeacher(SpecialistTeacher):
def __init__(self, specialistTeacher):
super().__init__(specialistTeacher)

def calculateSalary(self):
return super().calculateSalary() + 8000

def doWork(self):
super().doWork()
print("\n I am a specialist Physics Teacher. I teach Physics")


class SpecialistMathsTeacher(SpecialistTeacher):
def __init__(self, specialistTeacher):
super().__init__(specialistTeacher)

def calculateSalary(self):
return super().calculateSalary() + 10000

def doWork(self):
super().doWork()
print("\n I am a specialist Maths Teacher. I teach Maths")


class SpecialistChemistryTeacher(SpecialistTeacher):
def __init__(self, specialistTeacher):
super().__init__(specialistTeacher)

def calculateSalary(self):
return super().calculateSalary() + 7000

def doWork(self):
super().doWork()
print("\n I am a specialist Chemistry Teacher. I teach Chemistry")

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
specialistPhyTeacher = SpecialistPhysicsTeacher(SpecialistTeacher(BasicTeacher(10000)))

specialistPhyTeacher.doWork()

print("\n My Salary is ", specialistPhyTeacher.calculateSalary())

specialistphymathsTeacher = SpecialistMathsTeacher(SpecialistPhysicsTeacher
                                          (SpecialistTeacher(BasicTeacher(10000))))

specialistphymathsTeacher.doWork()

print("\n My Salary is ", specialistphymathsTeacher.calculateSalary())

If we run the above program, the output will look like the following:


I am a specialist Physics Teacher. I teach Physics


My Salary is  18000


 I am a specialist Physics Teacher. I teach Physics


 I am a specialist Maths Teacher. I teach Maths


 My Salary is  28000


Friday, August 25, 2023

The Template Method Design Pattern...

 It is a behavioral design pattern. It lets us define the skeleton of an algorithm, delegating some steps to the subclasses.

There are mainly two participants in this design pattern

- AbstractClass : It defines the abstract primitive methods that the subclasses will override. It also implements a template method which define the algorithm.

- ConcreteClass : it implements the abstract primitive methods of the Abstract Class.

Let us try to understand this design pattern from an example.

Suppose we are modeling the daily activity of an engineering student in college.

All students need to sign in and sign out in a common register. So these common tasks are part of the Base class.

However, each student has to attend the classes of his own stream - maybe Electronics, Computer Science, Mechanicals, etc.

So this part of the basic activity depends on the stream of the student and constitutes part of the Concrete class.

The UML diagram of the code is as follows:



Here is the source code of the Template Method Design Pattern

from abc import ABC, abstractmethod

class EngineeringStudent(ABC):
def __init__(self):
pass
def signIn(self):
print("\n Start of the day. I need to sign in the common register")
def signOut(self):
print("\n End of the day. I need to sign out in the common register")
@abstractmethod
def attendClass(self):
pass
def activityofAStudent(self):
self.signIn()
self.attendClass()
self.signOut()

class ElectronicsStudent(EngineeringStudent):

def __init__(self):
print("\n I am an Electronics Student")

def attendClass(self):
print("\n Attend the classes in the Electronics dept")

class ComputerScienceStudent(EngineeringStudent):
def __init__(self):
print("\n I am a CS Student")
def attendClass(self):
print("\n Attend the classes in the CS dept")


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
electronicsStudent = ElectronicsStudent()
electronicsStudent.activityofAStudent()
csStudent = ComputerScienceStudent()
csStudent.activityofAStudent()

# See PyCharm help at https://www.jetbrains.com/help/pycharm/

If we run the above program, the output will be as follows:


 I am an Electronics Student


 Start of the day. I need to  sign in the common register


 Attend the classes in the Electronics dept


 End of the day. I need to sign out in the common register


 I am a CS Student


 Start of the day. I need to  sign in the common register


 Attend the classes in the CS dept


 End of the day. I need to sign out in the common register


Thursday, August 24, 2023

Memento Design Pattern in Python...

This design pattern lets you save the state of an object without revealing the implementation.

There are mainly three participants in this design pattern

- Memento: stores the internal state of the Originator object. How much state of the Originator the memento will store completely depends upon the Originator

- Originator: It creates a memento containing a snapshot of its current internal state. It also uses the Memento to restore the Original state

Caretaker: It's responsible for the memento's safekeeping.

The memento design pattern helps to implement Undo facilities for any application. Think about a word processor app - at any point in time we can undo and get back the earlier state of the document - here lies the greatness of the memento design pattern.

The UML class diagram of the Memento pattern looks like the following:




The source code for the Memento Design Pattern is as follows:

cclass Originator:
    _state = ""

def set(self, state):
print(f"Originator: Setting state to {state}")
self._state = state

def save_to_memento(self):
return self.Memento(self._state)

def restore_from_memento(self, m) :
self._state = m.get_saved_state()
print(f"Originator: State after restoring from Memento: {self._state}")

class Memento:

def __init__(self, state):
self._state = state

def get_saved_state(self):
return self._state

class Caretaker:
def __init__(self, originator):
self.originator = originator
self.saved_states = []

def saveState(self):
self.saved_states.append(self.originator.save_to_memento())

def undo(self):
if not len(self.saved_states):
return
self.originator.restore_from_memento(self.saved_states.pop())

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
originator = Originator()
caretaker = Caretaker(originator)
originator.set("State1")
caretaker.saveState()
originator.set('State2')
caretaker.saveState()

originator.set("State3")
caretaker.saveState()

originator.set("State4")
caretaker.saveState()
print("\nClient: Now, let's rollback!\n")
caretaker.undo()
print("\nClient: Once more!\n")
caretaker.undo()

If we run the above lines of code, the output will be:


Originator: Setting state to State1
Originator: Setting state to State2
Originator: Setting state to State3
Originator: Setting state to State4

Client: Now, let's rollback!

Originator: State after restoring from Memento: State4

Client: Once more!

Originator: State after restoring from Memento: State3

Wednesday, August 23, 2023

Facade Design Pattern in Python...

This design pattern provides a simplified and unified interface to hide the inner complexities of several subsystems or libraries.

As most of the time, the user of a subsystem does not want to know about the internal complexities. He just wants a simplified interface to use the subsystem. Subsystems become complex as they evolve. A facade can provide this simplified interface to the users of the subsystem.

The main participants of the Facade design pattern are

- facade itself

- and the several subsystems

The subsystems have no knowledge about the facade - meaning they don't keep any reference to the facade.

Let me give you an example.

Suppose there are many geometrical shapes whose drawing functionalities are complex and each one must be drawn differently. But the client really does not want to go into that complexity.

Here comes the facade pattern in the rescue. This pattern will give a single method called drawShapes which will take care of all the internal complexity of the individual shapes.

The UML class diagram of the facade design pattern example looks like the following:


Here goes the source code of the example.

from abc import ABC, abstractmethod

class Shape(ABC):
@abstractmethod
def draw(self):
pass

class Circle(Shape):
def draw(self):
print("Special method to draw a circle")

class Rectangle(Shape):
def draw(self):
print("Special method to draw a rectangle")

class Triangle(Shape):
def draw(self):
print("Special method to draw a triangle")

class FacadeToShape:
def __init__(self, circle, rectangle, triangle):
self.circle = circle
self.rectangle = rectangle
self.triangle = triangle

def drawCircle(self):
self.circle.draw()
def drawRectangle(self):
self.rectangle.draw()
def drawTriangle(self):
self.triangle.draw()

def drawShapes(self):
self.drawCircle()
self.drawTriangle()
self.drawRectangle()


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
facateToShape = FacadeToShape(Circle(), Rectangle(), Triangle())
facateToShape.drawShapes()

Tuesday, August 22, 2023

Builder Design Pattern implemented using Python...

 Today I am presenting the Builder Pattern in Python.

As the name suggests - it is part of the creational pattern.

The idea is that if a class has many member variables - and the final object may not depend on all of them - and the number of parameters that the constructor takes varies - instead of making a lot of overloaded constructors, we use this Builder pattern

The code footprint is heavily reduced - as there is no need to create a matching number of overloaded constructors to match each and every permutation and combination of the member variables passed in the constructors.

In the given example, we have created a common Student class which may represent a 10th std, a 12th std, or an engineering student - maybe in 1st yr or 2nd year, or third year or maybe in the final fourth year.

In the case of a student who is a qualified engineer, we need to supply all the marks…

But in the case of a 2nd-year student - we don’t need to bother about third-year marks or fourth-year marks, the 10th, 12th, and 1st-year marks are sufficient to represent the object of a second-year student vis-a-vis marks.

Here goes the code for the CS students of the UNIVERSE.

from abc import  ABC, abstractmethod

class Student:
class Builder:

def __init__(self):
self.name=""
self.address = ""
self.tenthmarks = 0
self.twelfthmarks = 0
self.firstyrmarks = 0
self.secondyrmarks = 0
self.thirdyrmarks = 0
self.fourthyrmarks = 0

def setname(self, name):
self.name = name
return self
def setaddress(self, address):
self.address = address
return self
def settenthmarks(self, tenthmarks):
self.tenthmarks = tenthmarks
return self
def settwelfthmarks(self, twelfthmarks):
self.twelfthmarks = twelfthmarks
return self
def setfirstyrmarks(self, firstyrmarks):
self.firstyrmarks = firstyrmarks
return self
def setsecondyrmarks(self, secondyrmarks):
self.secondyrmarks = secondyrmarks
return self
def setthirdyrmarks9(self, thirdyrmarks):
self.thirdyrmarks = thirdyrmarks
return self
def setfourthyrmarks(self, fourthyrmarks):
self.fourthyrmarks = fourthyrmarks
return self

def build(self):
return Student(self)

def __init__(self, builder):
self.name = builder.name
self.addrees = builder.address
self.tenthmarks = builder.tenthmarks
self.twelfthmarks = builder.twelfthmarks
self.firstyrmarks = builder.firstyrmarks
self.secondyrmarks = builder.secondyrmarks
self.thirdyrmarks = builder.thirdyrmarks
self.fourthyrmarks = builder.fourthyrmarks

def displayData(self):
if self.name != "":
print("Name : " , self.name)

if self.addrees != "":
print("Address : ", self.addrees)

if self.tenthmarks != 0:
print("10th Marks : ", self.tenthmarks)

if self.twelfthmarks != 0:
print("12th Marks : ", self.twelfthmarks)

if self.firstyrmarks != 0:
print("1st Yr Marks : ",self.firstyrmarks)

if self.secondyrmarks != 0:
print("2nd Yr Marks : ", self.secondyrmarks)

if self.thirdyrmarks != 0:
print ("3rd Yr marks : ", self.thirdyrmarks)

if self.fourthyrmarks != 0:
print ("4th Yr Marks : ", self.fourthyrmarks)


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
ram12th = Student.Builder().setname("Ram").setaddress("Kolkata").
settenthmarks(50).build()

shyam2ndYr = Student.Builder().setname("Shyam").setaddress("Delhi")
.settenthmarks(70).settwelfthmarks(78).setfirstyrmarks(70).build()

ram12th.displayData()

shyam2ndYr.displayData()

If we run the above program, the output will be as follows:

Name :  Ram
Address :  Kolkata
10th Marks :  50

Name :  Shyam
Address :  Delhi
10th Marks :  70
12th Marks :  78
1st Yr Marks :  70

As it is clear for Ram, till 10th marks was important whereas, for Shyam, on the other hand, marks till 1st year are important.

Sunday, August 20, 2023

Visitor Pattern in Python...

 Visitor design pattern allows the addition of completely different functionalities to an existing class without much alteration in the original class.

Let me explain it with an example.

Suppose there are two items a shop sells - Book and Medicine

Now say, normally these two Item classes would look like two - what we call in Java as POJO classes where the most important attribute will be the price.

So far so good.

Now suppose the government is running 

- one literacy mission

and 

- one Health mission

Under these missions, few books are given huge discounts, and few medicines are sold at discounted prices.

Without the Visitor pattern, the algorithm of the discounts would have been put inside the POJO classes which might create maintenance problems in the future when the algorithm for discount changes.

With the visitor pattern, we encapsulate all these discount algorithms inside a special method called visit which comes from a Visitor interface.

So if it is a LiteracyMissionVisitor, the special algorithm offers a discount on special books whereas if it is a HealthMissionVisitor, the discount goes to specific medicines – all we have to do is to call accept on these special Book and Medicine objects passing the proper Visitor object,

That's it...

The UML class diagram looks as follows:




And here goes the source code of this Visitor Pattern

from abc import ABC, abstractmethod

class Visitor(ABC):
@abstractmethod
def visit(self, book):
pass
@abstractmethod
def visit(self, medicine):
pass

class Visitable(ABC):
@abstractmethod
def accept(self, visitor):
pass

class Book(Visitable):
def __init__(self, price):
self.price = price
def accept(self, visitor):
return visitor.visit(self)

def getPrice(self):
return self.price

class Medicine(Visitable):
def __init__(self, price):
self.price = price

def accept(self, visitor):
return visitor.visit(self)

def getPrice(self):
return self.price

class LiteracyMissionVisitor(Visitor):
def __init__(self, percentagediscountOnBook):
self.discount = percentagediscountOnBook
def visit(self, book):
book.price = book.price - (book.price * self.discount)/100
return book.price

class HealthMissionVisitor(Visitor):
def __init__(self, percentagediscountOnMedicine):
self.discount = percentagediscountOnMedicine

def visit(self, medicine):
medicine.price = medicine.price - (medicine.price * self.discount)/100
return medicine.price




# Press the green button in the gutter to run the script.
if __name__ == '__main__':

literacyMissionVisitor = LiteracyMissionVisitor(50)

chandaMama = Book(100)

print("Original price of the book is ", chandaMama.getPrice())

print("Due to literacy mission, there is huge discount on the book.
        After discount, the price is ", chandaMama.accept(literacyMissionVisitor))

healthDriveVisitor = HealthMissionVisitor(70)

vitaminDCapsule = Medicine(200)

print("Original price of the medinine is ", vitaminDCapsule.getPrice())

print("Due to health mission the reduced price of the
            medicine is ", vitaminDCapsule.accept(healthDriveVisitor))


If we run this program, the output will be as follows:

Original price of the book is  100

Due to literacy mission, there is huge discount on the book. After discount, the price is  50.0

Original price of the medinine is  200

Due to health  mission the reduced price of the medicine is  60.0




Saturday, August 19, 2023

Mediator Design Pattern in Python...

This design pattern lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.

The Mediator interface declares a method used by components to notify the mediator about various events. The Mediator may react to these events and triggers specific components to execute different yet specific tasks.

The Base Component provides the basic functionality of storing a mediator's reference inside the component.

Concrete Components implement various functionality. They don't depend on other components.

Let me explain it to you with an example.

Suppose two students Ridit and Rajdeep take a lot of responsibility in a class. But something bad happens between them, and hence they don't talk to each other. So, here comes the ClassMonitor - as a Mediator between Rajdeep and Ridit - if Ridit does anything that needs Rajdeep to do another task, Ridit notifies the Class Monitor, and then the Class Monitor asks Rajdeep to execute the necessary task.

Here's the class diagram of the Mediator Pattern

There are many uses for this design pattern. This design pattern can be found in most of the widget message-passing systems - individual widgets don't pass or communicate with each other - but they communicate through the container window.

For Android engineers - you remember how two fragments talk to each other through the container window.

Here goes the source code for this Design Pattern.

Enjoy.

Happy learning.

from abc import ABC, abstractmethod

class ClassMonitor(ABC):
@abstractmethod
def notify(self, sender, event):
pass
class ConcreteClassMonitor(ClassMonitor):
def __init__(self, student1, student2):
self.student1 = student1
self.student2 = student2

def notify(self, sender, event):
if event == "A":
print("The class Monitor reacts to event A and triggers Rajdeep to do task C")
self.student2.do_c()
elif event == "D":
print("The class Monitor reacts to event D and triggers Ridit to do Task B and Rajdeep to do Task C")
self.student1.do_b()
self.student2.do_c()

class BaseStudent:
def __init__(self, monitor):
self._monitor = monitor

def getMonitorr(self):
return self._monitor
def setMonitor(self, monitor):
self._monitor = monitor

class Ridit(BaseStudent):
def do_a(self):
print("Ridit does A.")
self._monitor.notify(self, "A")

def do_b(self):
print("Ridit does B.")
self._monitor.notify(self, "B")

class Rajdeep(BaseStudent):
def do_c(self):
print("Rajdeep does C.")
self._monitor.notify(self, "C")

def do_d(self):
print("Rajdeep does D")
self._monitor.notify(self, "D")

if __name__ == '__main__':
ridit = Ridit(None)
rajdeep = Rajdeep(None)
classMonitor = ConcreteClassMonitor(ridit,rajdeep)
ridit.setMonitor(classMonitor)
rajdeep.setMonitor(classMonitor)

print("Ma'am asks Ridit to do A")
ridit.do_a()

print("Ma'am asks Rajdeep to do D.")
rajdeep.do_d()
If we run the above program the output will be like the following:


Ma'am asks Ridit to do A
Ridit does A.
The class Monitor reacts to event A and triggers Rajdeep to do task C
Rajdeep does C.
Ma'am asks Rajdeep to do  D.
Rajdeep does D
The class Monitor reacts to event D and triggers Ridit to do Task B and Rajdeep to do Task C
Ridit does B.
Rajdeep does C.