SDA Assignment 3
SDA Assignment 3
BSE-4A
1. Compare and contrast the following architectural styles and also mention the types of
applications and situations when each of them is preferred. Use diagrams or any suitable
pseudo-code to support your answer:
a. Peer to Peer & Client/Server
b. Batch Sequential & Pipe and Filter
c. Repository & Blackboard
ANSWER:
1. Peer-to-Peer (P2P) vs. Client/Server
a. Peer-to-Peer (P2P)
Concept: In a P2P network, each device acts as both a client and a server, directly
requesting and providing resources to each other. There's no central coordinating
server.
Diagram:
Applications:
o File sharing (e.g., BitTorrent)
o Collaborative editing (e.g., Google Docs with real-time updates)
o Online gaming (e.g., some multiplayer games establish P2P connections)
Advantages:
o Scalability: The network can grow by adding more devices without a central
bottleneck.
o Decentralization: No single point of failure, as all devices contribute.
o Cost-effective: No dedicated server hardware required.
Disadvantages:
o Security: Requires strong authentication and authorization mechanisms to
prevent unauthorized access.
o Performance: Relies on individual device capabilities, so performance can vary.
o Discovery: Finding resources within the network can be challenging.
b. Client-Server
Concept: A dedicated server acts as a central resource provider, responding to requests
from clients.
Diagram:
Applications:
o Web applications (e.g., online stores, social media)
o Email servers
o Database systems
Advantages:
o Centralized control: Easier management and security.
o Scalability: The server can be upgraded to handle more clients.
o Performance: Server can be optimized for specific tasks, leading to better
performance.
Disadvantages:
o Single point of failure: If the server goes down, all clients are affected.
o Cost: Requires dedicated server hardware and maintenance.
Applications:
o Database systems
o Configuration management
o Version control systems
b. Blackboard
Concept: A shared space where processes or threads can read and write data without
direct interaction. Offers a more lightweight and flexible approach.
Diagram:
Applications:
o Artificial Intelligence Systems (Expert systems that use a blackboard to store and
update knowledge based on the contributions of various inference engines)
o Collaborative Problem-Solving Environments (Systems where multiple agents
work together to solve complex problems by sharing partial solutions and data)
o Complex Control Systems (Robotics or autonomous vehicle systems that use a
blackboard to manage and integrate sensory data and control commands)
2. Compare and contrast the following design patterns and also mention the types of
applications and situations when each of them is preferred. Use diagrams and any suitable
code to support your answer:
ANSWER
Both Chain of Responsibility and Command patterns are behavioral patterns that promote loose
coupling between objects involved in handling requests. Their main differences are:
Chain of Responsibility:
Concept: Imagine a line of people waiting to be served at a counter. Each person (object) in the
line checks if they can handle the request (serve the customer). If they can't, they pass the request
(customer) to the next person (object) in line. This continues until someone can handle the
request or the end of the line is reached.
Applications:
o Event handling: In a user interface, different objects can be responsible for handling
user interactions like button clicks. A click event might pass through a chain of controls
(objects) until one of them decides to take action (e.g., open a dialog box).
o Authorization checks: A user request might be passed through a chain of authorization
handlers, each verifying a specific permission before granting access.
o Error handling: Different objects can be responsible for handling specific error types.
An error might propagate through a chain until a dedicated handler takes care of it.
Code Example (Python):
class Handler:
def __init__(self, successor=None):
self.successor = successor
class TextProcessor(Handler):
def can_handle(self, request):
return request.type == "text"
class ImageProcessor(Handler):
def can_handle(self, request):
return request.type == "image"
# Usage
processor1 = TextProcessor(ImageProcessor()) # TextProcessor first, then ImageProcessor
request1 = {"type": "text", "data": "Hello, world!"}
processor1.handle(request1) # TextProcessor handles this request
Command:
Concept: Imagine a waiter taking an order (request) from a customer. The waiter doesn't
necessarily need to know how to prepare the food (execute the request). Instead, they write down
the order (encapsulate the request) and give it to the chef (receiver) who knows how to cook
(execute the request based on the order).
Applications:
o Undo/redo functionality: A command object can store the information needed to undo
or redo an action.
o Queuing and scheduling tasks: Tasks can be represented as commands and added to a
queue or scheduled for execution at a specific time.
o Making requests asynchronous: Commands can be used to decouple the request from
the actual execution, allowing for asynchronous processing.
Code Example (Python):
class Command:
def __init__(self, receiver):
self.receiver = receiver
def execute(self):
raise NotImplementedError
class OpenFileCommand(Command):
def __init__(self, receiver, filename):
super().__init__(receiver)
self.filename = filename
def execute(self):
self.receiver.open_file(self.filename)
class Receiver:
def open_file(self, filename):
print(f"Opening file: {filename}")
# Usage
receiver = TextEditor()
command = OpenFileCommand(receiver, "document.txt")
command.execute() # Open "document.txt" in the TextEditor
Similarities:
Both patterns decouple the request sender from the receiver, promoting flexibility.
Both can be used to chain multiple operations.
Differences:
Focus: Chain of Responsibility focuses on passing requests through a chain of potential handlers
until one processes it.
Encapsulation: Command focuses on encapsulating the request itself, separating it from the
invoker and the receiver.
def operation2(self):
# Complex implementation
pass
class Facade:
def __init__(self, system):
self.system = system
def simplified_operation(self):
self.system.operation1()
self.system.operation2()
# Usage
facade = Facade(ComplexSystem())
facade.simplified_operation() # Simplified access to complex operations
Decorator
Concept: Dynamically adds or modifies the behavior of an object at runtime by wrapping it in
another object (decorator). Think of decorating a cake with frosting and sprinkles. The cake
(original object) remains the same, but its behavior (appearance and taste) is enhanced by the
decorator (frosting and sprinkles).
Applications:
o Adding functionality to existing objects without modifying their source code (e.g., adding
logging or authentication to database access)
o Providing a flexible way to create different combinations of functionalities (e.g., building
a UI by combining different decorator components like borders and rounded corners)
Code Example (Python):
class Text:
def __init__(self, data):
self.data = data
def render(self):
return self.data
class BoldText(Decorator):
def __init__(self, component):
super().__init__(component)
def render(self):
return f"<b>{self.component.render()}</b>" # Wrap in bold tags
# Usage
text = Text("Hello, world!")
bold_text = BoldText(text)
print(bold_text.render()) # Prints "<b>Hello, world!</b>"
Similarities:
Both patterns provide a simplified interface to underlying complexities.
Differences:
Focus: Façade focuses on hiding the complexity of a system and offering a unified entry point.
Object Modification: Decorator dynamically modifies the behavior of an object at runtime by
wrapping it.
Mediator
Concept: Acts as a central communication hub between objects, facilitating interaction without
them needing to know about each other directly. Imagine a meeting room coordinator who
manages communication and interactions between participants (objects) without them needing to
directly contact each other.
Applications:
o Decoupling objects in a complex system (e.g., objects in a user interface communicating
through a mediator)
o Simplifying communication logic (e.g., managing notifications between different
components in an application)
o Promoting loose coupling and easier maintenance (changes in one object don't directly
affect others)
Similarities:
o Both patterns control interactions between objects.
Differences:
o Focus: Proxy focuses on controlling access to a service and potentially modifying
requests/responses.
o Communication: Mediator manages communication between multiple objects,
facilitating interactions without direct references.
o Knowledge: Objects using a proxy typically don't know about the actual service. Objects
using a mediator might be aware of the mediator but not necessarily of each other.