Sie sind auf Seite 1von 22

Software Design Laboratory

Subject Code : 10MCA56


Hours/Week : 3
Total Hours
: 42

I.A Marks
: 50
Exam Hours : 03
Exam Marks : 50

The student has to draw the necessary analysis and design diagrams in UML,
using any suitable UML Drawing Tool and implement in Java OR C++ OR C# a program
to demonstrate the Design Pattern specified by the Examiner. For each pattern, an
example is listed here.
However, student is free to choose to solve any suitable problem to
demonstrate the specified pattern. The Design Pattern is allotted based on lots from
the following list:
1)Publisher-Subscriber: (Communication)
Example: An embedded application; An interrupt-driven module keeps track of
temperature of the furnace. When the temperature is beyond preset upper / lower limits, a
module that controls the heating element must be informed. Another module that displays
an indicator also needs to know of such a change. Further, a log module also needs this
information.
2)Command Processor: (Management)
Example: A simple Text Editor; Facilities provided include making the text bold,
making the text into all upper case; An Undo feature is to be implemented.
3)Forwarder-Receiver: (Communication)
Example: A simple peer-to-peer message exchange scenario; Underlying
communication protocol is TCP/IP.
4)Client-Dispatcher-Server: (Communication)
Example: A simplified implementation of RPC
5)Proxy: (Access Control)
Example: A highly simplified implementation of a proxy web server.
6)Whole-Part: (Structural Decomposition)
Example: Implementation of any collection like a set.
7)Master-Slave: (Organization of work)
Example: A multithreaded implementation of any parallelized divide-and-conquer
algorithm

1)

Publishers-Subscriber / Observer Pattern (Communication)


Intent: Define a one-to-many dependency between objects so that when one object
changes state, all its dependents are notified and updated automatically.
Structure:

Subject: Keeps track of its observers. Provides an interface for attaching and detaching
Observer objects
Observer: Defines an interface for update notification
ConcreteSubject: The object being observed. stores state of interest to ConcreteObserver
objects. Sends a notification to its observers when its state changes
ConcreteObserver: The observing object. Stores state that should stay consistent with
the subject's. Implements the Observer update interface to keep its state consistent with
the
The Class diagram:

Java Code:
WeatherData.java
package Observer;
import java.util.Observable;
public class WeatherData extends Observable {
private float temprature;
public float getTemprature() {
return temprature;
}
private float pressure;
public float getPressure() {
return pressure;
}
private float humidity;
public float getHumidity() {
return humidity;
}
public void measurementschanged(){
setChanged();
notifyObservers();
}
public void setMeasurements(float theTemprature,float theHumidity,float thePressure){
temprature=theTemprature;
pressure=thePressure;
humidity=theHumidity;
measurementschanged();
}
}
ForeCastDisplay.java:
package Observer;
import java.util.Observable;
import java.util.Observer;
public class ForeCastDisplay implements Observer {
private float currentPressure = 29.92f;
private float lastPressure;
public ForeCastDisplay(Observable observable) {
observable.addObserver(this);
}
public void update(Observable observable, Object arg) {
if (observable instanceof WeatherData) {
WeatherData weatherData = (WeatherData)observable;

lastPressure = currentPressure;
currentPressure = weatherData.getPressure();
display();
}
}
public void display() {
System.out.print("Forecast: ");
if (currentPressure > lastPressure) {
System.out.println("Improving weather on the way!");
} else if (currentPressure == lastPressure) {
System.out.println("More of the same");
} else if (currentPressure < lastPressure) {
System.out.println("Watch out for cooler, rainy weather");
}
}
}
CurrentConditionDIsplay.java:
package Observer;
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionDisplay implements Observer {
private float temprature;
private float humidity;
Observable observable;
public CurrentConditionDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temprature = weatherData.getTemprature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temprature
+ "F degrees and " + humidity + "% humidity");
}
}
The Client:
package Observer;

public class WeatherStation {


public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionDispaly currentConditions = new CurrentConditionDispaly(weatherData);
ForeCastDisplay forecastDisplay = new ForeCastDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}

2)

Command Pattern (Management)

Intent: Encapsulate a request as an object, thereby letting you parameterize clients with
different requests, queue or log requests, and support undoable operations.
Also Known As: Action, Transaction
Applicability:
Use the command design pattern when we want to:
1) Implement a callback functionality.
2) Specify, queue, and execute requests at different times.
3) Support undo and change operation.
4) Structure a system around high-level operations built on primitives operations.
Structure:

Collaborations:
1)
2)
3)
4)

the client creates a ConcreteCommand object and specifies its receiver.


An invoker object stores the ConcreteCommand object.
The invoker issues a request by calling Execute on the Command.
The ConcreteCommand object invokes operations on its receiver to carry out the
request.

Participants:
Command: declares and interface for executing an operation
ConcreteCommand: defines a binding between a Receiver object and an action.
Implements: Execute by invoking the corresponding Operation(s) on Receiver.
Client: creates a ConcreteCommand object and sets its receiver.
Invoker: asks the command to carry out the request.
Receiver: knows how to perform the operations associated with carrying out a request.
Any class may serve as a receiver.
Consequences:
1) Command decouples the object that invokes the operation from the one that
knows how to perform it.
2) Command are first-class objects. They can be manipulated and extended like any
other object.
3) Command can be made into a composite command.
4) Its easy to add new Commands, because you dont have to change existing
classes.
Example:
Consider a simple switch. In this example we configure the Switch with 2 commands: to
turn the light on and to turn the light off.
A benefit of this particular implementation of the command Pattern is that the switch can
be used with any device, not just a light - the Switch in the following example turns a
light on and off, but the Switch's constructor is able to accept any subclasses of

Command for its 2 parameters. For example, you could configure the Switch to start an
engine.
Class Diagram:

Java Code:
/*the Invoker class*/
public class Switch {
private Command flipUpCommand,flipDownCommand;
public Switch(Command flipUpCmd,Command flipDownCmd){
this.flipUpCommand=flipUpCmd;
this.flipDownCommand=flipDownCmd;
}
public void flipUp(){
flipUpCommand.execute();
}
public void flipDown(){
flipDownCommand.execute();
}
}
/*Receiver class*/
public class Light{
public void turnOn(){
System.out.println("The light is on");
}
public void turnOff(){
System.out.println("The light is off");
}

}
/*the Command interface*/
public interface Command{
void execute();
}
/*the Command for turning on the light*/
public class FlipUpCommand implements Command{
private Light theLight;
public FlipUpCommand(Light light){
this.theLight=light;
}
public void execute(){
theLight.turnOn();
}
}
/*the Command for turning off the light*/
public class FlipDownCommand implements Command{
private Light theLight;
public FlipDownCommand(Light light){
this.theLight=light;
}
public void execute(){
theLight.turnOff();
}
}
/*The test class or client*/
public class PressSwitch{
public static void main(String[] args){
Light lamp = new Light();
Command switchUp=new FlipUpCommand(lamp);
Command switchDown=new FlipDownCommand(lamp);
Switch s=new Switch(switchUp,switchDown);
try {
s.flipUp();
s.flipDown();
s.flipUp();
s.flipDown();
} catch (Exception e){
System.out.println("Argument's required.");
}
}
}

3) Forwarder and Receiver Pattern (Communication)


Intent: The Forwarder-Receiver design pattern provides transparent inter process
communication for software systems with a peer-to-peer interaction model. It
introduces forwarders and receivers to decouple peers from the underlying
communication mechanisms.
Structure:

Participents:
Peer components are responsible for application tasks. To carry out their tasks peers
need to communicate with other peers.
Forwarder components are responsible for forwarding all these messages to remote
network agents without introducing any dependencies on the underlying IPC
mechanisms.
Receiver components are responsible for receiving messages. A receiver offers a
general interface that is an abstraction of a particular IPC mechanism. It includes
functionality for receiving and unmarshaling messages.

Class Diagram:

Java Code:
Entry.java:
class Entry {
private String destinationId; // target machine
private int portNr; // socket port
public Entry(String theDest, int theport) {
destinationId = theDest;
portNr = theport;
}
public String dest() {
return destinationId;
}
public int port() {
return portNr;
}
}
Message.java:
class Message {
public String sender;
public String data;
public Message(String thesender, String rawData) {
sender = thesender;
data = rawData;
}
}

Registry.java:
import java.util.*;
class Registry {
private Hashtable hTable = new Hashtable() ;
public void put (String theKey, Entry theEntry) {
hTable.put(theKey,theEntry);
}
public Entry get(String aKey) {
return (Entry) hTable.get (aKey) ;
}
}
Forwarder.java:
import java.io.*;
import java.net.Socket;
public class Forwarder {
public Server Forwarder;
private Socket s;
private OutputStream oStr;
private String myName;
private Registry reg;
public Forwarder(String theName,Registry reg) {
myName = theName;
this.reg=reg;
}
private byte[] marshal (Message theMsg) {
return theMsg.data.getBytes();
}
private void deliver(String theDest, byte[] data) {
try
{
Entry entry = reg.get (theDest) ;
s = new Socket(entry.dest() ,entry.port());
oStr = s.getOutputStream();
oStr.write(data);
oStr.flush() ;
oStr.close();
s.close() ;
}
catch(IOException e){
System.out.println("For error"+e);
}
}
public void sendMsg (String theDest , Message theMsg) {
deliver(theDest, marshal(theMsg) );
}
}

Receiver.java:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Receiver {
private ServerSocket srvS;
private Registry reg;
private Socket s;
private InputStream iStr;
private String myName;
public Reciver(String theName,Registry reg)
{
myName = theName;
this.reg=reg;
try {
Entry entry = reg.get(myName) ;
srvS = new ServerSocket(entry.port());
System.out.println("Server started");
}catch(Exception e){e.printStackTrace();}
}
private Message unmarshal (byte [] anarray) {
return new Message(myName,new String(anarray));
}
private byte[] receive()
{
int val;
byte buffer [] = null;
try {
s = srvS.accept();
iStr = s.getInputStream();
val = iStr. read ( ) ;
buffer = new byte [val] ;
iStr.read(buffer) ;
iStr.close();
s.close();
srvS.close();
}
catch(IOException e) { System.out.println("Error"+ e);}
return buffer;
}
public Message receiveMsg (){
return unmarshal(receive()) ;
}
private void IPCmsg() {
}
}

Server.java:
class Server {
Reciver r;
Forwarder f;
static Registry reg=new Registry();
public void execute()
{
Message result = null;
r = new Reciver ( "Server",reg) ;
f = new Forwarder ("Server" ,reg) ;
Message msg = new Message ("Server","I am alive");
f . sendMsg ("Server", msg) ;
result = r. receiveMsg ( );
System.out.println( result.data.trim());
}
public static void main(String args[])
{
Entry entry = new Entry ("127.0.0.1", 2900) ;
reg.put("Client", entry);
entry = new Entry ("127.0.0.1",2900) ;
reg.put("Server", entry);
new Server().execute();
}
}

4) Client Dispatcher Pattern (Communication)


Intent: The Client-Dispatcher-Server design pattern introduces an intermediate layer
between clients and servers, the dispatcher component. It provides location transparency
by means of a name service, and hides the details of the establishment of the
communication connection between clients and servers.
Structure:

Collaboration:

Participants:
Client: The task of a client is to perform domain-specific tasks. The client accesses operations
offered by servers in order to carry out its processing tasks. Before sending a request to a server,
the client asks the dispatcher for a communication channel. The client uses this channel to
communicate with the server.
Server: A server provides a set of operations to clients. It either registers itself or is registered
with the dispatcher by its name and address. A server component may be located on the same
computer as a client, or may be reachable via a network.
Dispatcher: The dispatcher offers functionality for establishing communication channels
between clients and servers. To do this, it takes the name of a server component and maps this
name to the physical location of the server component. The dispatcher establishes a
communication link to the server using the available communication mechanism and returns a
communication handle to the client. If the dispatcher cannot initiate a communication link with

the requested server, it informs the client about the error it encountered. To provide its
name service, the dispatcher implements functions for registering and locating servers.
The Class diagram:

Java Code:
//CDS.java
public class CDS {
public static Dispatcher disp = new Dispatcher();
public static void main(String[] args) {
Service sl = new PrintService("printSvc1","srvl");
Service s2 = new PrintService("printSvc2","srv2");
Client client = new Client ();
client.doTask ();
}
}
//Dispatcher.java
import java.util.*;
import java.io.*;
public class Dispatcher {
private Client client;
private PrintService printservice;
Hashtable registry = new Hashtable();
Random rnd = new Random(123456); // for random access
public void registerService(String svc, Service obj) {
Vector v = (Vector) registry. get (svc) ;
if (v == null) {
v = new Vector ();
registry.put(svc, v) ;
}
v.addElement(obj);
}
public void unregisterService() {
}
public Service locateServer(String svc)throws NotFound {
Vector v = (Vector) registry .get (svc) ;
if (v == null) throw new NotFound ( ) ;
if (v.size() == 0) throw new NotFound();
int i = rnd.nextInt () % v.size() ;
return (Service) v. elementAt (i) ;
}
public void establishChannel() {
}
public void getChannel() {
}
}
//Service.java (an abstract class to provide runService method and to register all the Services to the
dispatcher, it is the server participant)
public abstract class Service {
String nameofservice; // service name
String nameofserver; // server name
public Service(String svc, String srv) {
nameofservice = svc;
nameofserver = srv;
CDS.disp.registerService(nameofservice,this) ;
}
abstract public void runService() ; // service provided
}

//PrintService.java (A real service class extending the abstract class Service)


public class PrintService extends Service{
private Dispatcher dispatcher;
private Client client;
public PrintService(String svc, String srv) {
super(svc, srv);
}
public void acceptConnection() {
}
public void runService() {
//test output
System.out.println("Service " + nameofservice + " by " + nameofserver);
//here the service code would be implemented
}
public void receiveRequest() {
}
}
//Client.java:( A client class with do Task operation)
public class Client {
private Dispatcher dispatcher;
private PrintService printservice;
public void doTask() {
Service s;
try {
s = CDS .disp. locateServer ("printSvc1") ;
s . runService ( ) ;
}catch (NotFound n) {
System.out .println ("Not available") ;
}
try {
s = CDS .disp.locateServer("printSvc2");
s .runService ( ) ;
}catch (NotFound n) {
System.out.println("Not available");
}
try {
s = CDS .disp.locateServer("drawSvc");
s .runService () ;
}catch (NotFound n) {
System.out.println("Not available") ;
}
}
public void sendRequest() {
}
}
Output:
Service printSvc1 by srvl
Service printSvc2 by srv2
Not available

5) Proxy Pattern (Access Control)


Intent: Provide a surrogate or placeholder for another object to control access to it
Motivation:
1.A proxy is
-a person authorized to act for another person
-an agent or substitute
-the authority to act for another
2.There are situations in which a client does not or can not reference an object directly,
but wants to still interact with the object
3.A proxy object can act as the intermediary between the client and the target object
The proxy object has the same interface as the target object
The proxy holds a reference to the target object and can forward requests to the target as
required (delegation!)
In effect, the proxy object has the authority the act on behalf of the client to interact with
the target object
Applicability:
Proxies are useful wherever there is a need for a more sophisticated reference to a object
than a simple pointer or simple reference can provide
Types of Proxies:
Remote Proxy - Provides a reference to an object located in a different address space on
the same or different machine
Virtual Proxy - Allows the creation of a memory intensive object on demand. The object
will not be created until it is really needed.
Copy-On-Write Proxy - Defers copying (cloning) a target object until required by client
actions. Really a form of virtual proxy.
Protection (Access) Proxy - Provides different clients with different levels of access to a
target object
Cache Proxy - Provides temporary storage of the results of expensive target operations
so that multiple clients can share the results
Firewall Proxy - Protects targets from bad clients (or vice versa)
Synchronization Proxy - Provides multiple accesses to a target object
Smart Reference Proxy - Provides additional actions whenever a target object is
referenced such as counting the number of references to the object

Structure:

Collaboration:

Example:Proxy
Imagine that we are creating an Application that is making use of email-service such as
send and receive email.. Assuming that the Client Application won't be always accessing
the Email Service, the Email Service is an ideal candidate to be modeled as a Virtual
Proxy.

Use Case Diagram:

Class Diagram:

The Sequence Diagram for EmailServices

The Collaboration Diagram:

The Java Code :


EMailService.java
public interface EMailService {
public void sendMail(String receiver,String subject,String text);
public void receiveMail(String receiver);
}
The above is the interface declaration for EMailService which provides methods for
sending and receiving mails through its sendMail() and receiveMail() methods. Now,
let us look into the real implementation for this EMailService interface.
RealEMailService.java
public class RealEMailService implements EMailService {
public void sendMail(String receiver,String subject,String text)
{
System.out.println("Sending mail to'" + receiver + "'" + "with subject '" +
subject + "'" + "
and message '" + text + "'");
}
public void receiveMail(String receiver) {
System.out.println("Receiving mail from '" + receiver + "'");
}
}
As we see, the above class should be loaded on demand only, i.e, an instance for the
above class should be created only when the client is accessing for the first time.
Now, let us create a proxy class for the above real implementation. It should be
noted that the proxy class should conform to the methods of the real implementation
class so that the clients are provided with a single unified interface. In many
instances, the clients are even unaware of the fact that they are making calls on the
proxy. The following proxy implementation implements the EMailService interface
and just delegates the method calls to the real implementation. It means that the
proxy class should maintain a reference to the original real class object and should
create the real object on demand.
ProxyEMailService.java
public class ProxyEMailService implements EMailService {
private RealEMailService emailService;
public void receiveMail(String receiver) {
if (emailService == null){
emailService = new RealEMailService();
}
emailService.receiveMail(receiver);

}
public void sendMail(String receiver, String subject, String text) {
if (emailService == null){
emailService = new RealEMailService();
}
emailService.sendMail(receiver, subject, text);
}
}
Now, let us look into the Application class which is going to be accessible by the
Clients.
Application.java
public class Application {
public EMailService locateEMailService(){
EMailService emailService = new ProxyEMailService();
return emailService;
}
}
In the above class, we actually create an object reference for the proxy
implementation and not for the real implementation. Clients are unaware that they
are dealing with the proxy object.
Testing the code:
ApplicationClient.java
public class ApplicationClient {
public static void main(String[] args) {
// TODO Auto-generated method stub
Application application = new Application();
EMailService emailService = application.locateEMailService();
emailService.sendMail("abc@gmail.com", "Hello", "A test mail");
emailService.receiveMail("abc@gmail.com");
}
}
Output:
Sending mail to 'abc@gmail.com' with subject 'Hello' and message 'A test mail'
Receiving mail from 'abc@gmail.com'