40
1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

Embed Size (px)

Citation preview

Page 1: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

1

ECE 355: Software Engineering

CHAPTER 8

Instructor

Kostas Kontogiannis

Page 2: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

2

Course outline

• Unit 1: Software Engineering Basics • Unit 2: Process Models and Software Life Cycles• Unit 3: Software Requirements • Unit 4: Unified Modeling Language (UML)• Unit 5: Design Basics and Software Architecture• Unit 6: OO Analysis and Design Unit 7: Design Patterns• Unit 8: Testing and Reliability • Unit 9: Software Engineering Management and Economics

Page 3: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

3

References

• The material for this lecture was obtained from

– http://www.dofactory.com/Patterns/Patterns.aspx#list

– http://www.developer.com/design/article.php/1502691

Page 4: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

5

Adapter Design Pattern

• The Adapter is intended to provide a way for a client to use an object whose interface is different from the one expected by the client, without having to modify either

• This pattern is suitable for solving issues that arise, for example, when: – 1) you want to replace one class with another and the

interfaces do not match, and – 2) you want to create a class that can interact with other

classes without knowing their interfaces at design time

Page 5: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

6

Adapter Design Pattern - Operation

• First, you create a custom Target class that defines methods using an interface as expected by the client

• Second, you create a custom Adapter that implements the interface expected by the Adaptee. The Adapter class subclasses the Target, and provides an alternate implementation of the client requests in terms that the Adaptee expects. Adapter overrides the Target method and provides the correct interface for Adaptee.

• This approach has the advantage that it does not lead to modifications in the client. Adapter is a structural pattern and you can use it to react to changes in class interfaces as your system evolves, or you can proactively use the Adapter pattern to build systems that anticipate changing structural details

Page 6: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

7

Adapter Design Pattern

Page 7: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

8

Adapter Design Pattern

• Participants: The classes and/or objects participating in this pattern are:

• Target   – defines the domain-specific interface that Client uses.

• Adapter  – adapts the interface Adaptee to the Target interface.

• Adaptee   – defines an existing interface that needs adapting.

• Client  – collaborates with objects conforming to the Target interface.

Page 8: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

9

Adapter Design Pattern

  // "Target"

  class Target  {    public virtual void Request()    {      Console.WriteLine("Called Target Request()");    }  }

class Adapter : Target  {    private Adaptee adaptee = new Adaptee();

    public override void Request()    {      // Possibly do some other work       // and then call SpecificRequest       adaptee.SpecificRequest();    }  }

  

   // "Adaptee"

  class Adaptee  {    public void SpecificRequest()    {      Console.WriteLine("Called SpecificRequest()");    }  }}

// Client

  class MainApp  {    static void Main()    {      // Create adapter and place a request       Target target = new Adapter();      target.Request();

      // Wait for user       Console.Read();    }  }

Output Called SpecificRequest()

Page 9: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

10

Bridge Design Pattern - Operation

• Decouple an abstraction from its implementation so that the two can vary independently

• The Bridge pattern is useful when there is a hierarchy of abstractions and a corresponding hierarchy of implementations. Rather than combining the abstractions and implementations into many distinct classes, the Bridge pattern implements the abstractions and implementations as independent classes that can be combined dynamically. Related patterns are :

– Layered Architecture The Bridge design pattern is a way of organizing the entities identified using the Layered Architecture pattern into classes.  

– Abstract Factory The Abstract Factory pattern can be used by the Bridge pattern to decide which implementation class to instantiate for an abstraction object

Page 10: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

11

Bridge Design Pattern

• Abstraction  – defines the abstraction's interface. – maintains a reference to an object of type Implementor.

• RefinedAbstraction   – extends the interface defined by Abstraction.

• Implementor  – defines the interface for implementation classes. This interface doesn't

have to correspond exactly to Abstraction's interface; in fact the two interfaces can be quite different. Typically the Implementation interface provides only primitive operations, and Abstraction defines higher-level operations based on these primitives.

• ConcreteImplementor  – implements the Implementor interface and defines its concrete

implementation.

Page 11: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

12

Bridge Design Pattern

Page 12: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

13

Bridge Design Pattern

  // "Abstraction"

  class Abstraction  {    protected Implementor implementor;

    // Property

    public Implementor Implementor    {      set{ implementor = value; }    }

    public virtual void Operation()    {      implementor.Operation();    }  }  

// "Implementor"

  abstract class Implementor  {    public abstract void Operation();  }

  // "RefinedAbstraction"

  class RefinedAbstraction : Abstraction  {    public override void Operation()    {      implementor.Operation();    }  }

  

Page 13: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

14

Bridge Design Pattern

// "ConcreteImplementorA"

  class ConcreteImplementorA : Implementor  {    public override void Operation()    {      Console.WriteLine("ConcreteImplementorA Operation");    }  }

  // "ConcreteImplementorB"

  class ConcreteImplementorB : Implementor  {    public override void Operation()    {      Console.WriteLine("ConcreteImplementorB Operation");    }  }

Page 14: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

15

Bridge Design Pattern - Client

class MainApp  {    static void Main()    {      Abstraction ab = new RefinedAbstraction();

      // Set implementation and call       ab.Implementor = new ConcreteImplementorA();      ab.Operation();

      // Change implemention and call       ab.Implementor = new ConcreteImplementorB();      ab.Operation();

      // Wait for user       Console.Read();    }  }

Output ConcreteImplementorA OperationConcreteImplementorB Operation

Page 15: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

16

State Design Pattern - Operation• Allow an object to alter its behavior when its internal state

changes. The object will appear to change its class.

• The State pattern is useful when you want to have an object represent the state of an application, and you want to change the state by changing that object.

• The State pattern is intended to provide a mechanism to allow an object to alter its behavior in response to internal state changes. To the client, it appears as though the object has changed its class.

• The benefit of the State pattern is that state-specific logic is localized in classes that represent that state.

Page 16: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

17

State Design Pattern

Participants: The classes and/or objects participating in this pattern are:

• Context – defines the interface of interest to clients – maintains an instance of a ConcreteState subclass that defines the

current state. • State

– defines an interface for encapsulating the behavior associated with a particular state of the Context.

• Concrete State – each subclass implements a behavior associated with a state of

Context

Page 17: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

18

State Design Pattern

Page 18: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

19

State Design Pattern// "State"

  abstract class State  {

    public abstract void Handle(Context context);  }

  // "ConcreteStateA"

  class ConcreteStateA : State  {    public override void Handle(Context context)    {      context.State = new ConcreteStateB();    }  }

  // "ConcreteStateB"

  class ConcreteStateB : State  {    public override void Handle(Context context)    {      context.State = new ConcreteStateA();    }  }

class Context  {    private State state;

    public Context(State Astate)    {      this.state = Astate;    }

    // Property     public State State    {      get{ return state; }      set      {         state = value;         Console.WriteLine("State: " + state.GetType().Name);      }    }

    public void Request()    {      state.Handle(this);    }

  }

Page 19: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

20

State Design Pattern - Client

static void Main()    {      // Setup context in a state       Context c = new Context(new ConcreteStateA());

      // Issue requests, which toggles state       c.Request();      c.Request();      c.Request();      c.Request();

      // Wait for user       Console.Read();    }  }

Output

State: ConcreteStateAState: ConcreteStateBState: ConcreteStateAState: ConcreteStateBState: ConcreteStateA

Page 20: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

21

Factory Method - Operation

• When developing classes, you always provide constructors for your clients' use. There are certain circumstances in which you do not want your clients to know which class out of several to instantiate.

• The Factory Method is intended to define an interface for clients to use to create an object, but lets subclasses decide which class to instantiate. Factory Methods let a class defer instantiation to subclasses.

Page 21: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

22

Factory Method

• The classes and/or objects participating in this pattern are:

• Product– defines the interface of objects the factory method creates

• ConcreteProduct– implements the Product interface

• Creator – declares the factory method, which returns an object of type Product.

Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object.

– may call the factory method to create a Product object. • ConcreteCreator 

– overrides the factory method to return an instance of a ConcreteProduct.

Page 22: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

23

Factory Method

Page 23: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

24

Factory Method  abstract class Product

  {  }

  // "ConcreteProductA"

  class ConcreteProductA : Product  {  }

  // "ConcreteProductB"

  class ConcreteProductB : Product  {  }

  // "Creator"

  abstract class Creator  {    public abstract Product FactoryMethod();  }

// "ConcreteCreator"

  class ConcreteCreatorA : Creator  {    public override Product FactoryMethod()    {      return new ConcreteProductA();    }  }

  // "ConcreteCreator"

  class ConcreteCreatorB : Creator  {    public override Product FactoryMethod()    {      return new ConcreteProductB();    }  }}

Page 24: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

25

Factory Method - Client  class MainApp

  {    static void Main()    {      // An array of creators       Creator[] creators = new Creator[2];      creators[0] = new ConcreteCreatorA();      creators[1] = new ConcreteCreatorB();

      // Iterate over creators and create products

      foreach(Creator creator in creators)      {         Product product = creator.FactoryMethod();         Console.WriteLine("Created {0}",           product.GetType().Name);      }

      // Wait for user        Console.Read();    }  }

Output: Created ConcreteProductACreated ConcreteProductB

Page 25: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

26

Command Design Pattern - Operation

• The Command pattern is intended to encapsulate a request as an object. For example, consider a window application that needs to make requests of objects responsible for the user interface.

• The client responds to input from the user by creating a command object and the receiver. It then passes this object to an Invoker object, which then takes the appropriate action. This allows the client to make requests without having to know anything about what action will take place.

• In addition, you can change that action without affecting the client. Practical uses for Command are for creating queues and stacks for supporting "undo" operations, configuration changes, and so on.

Page 26: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

27

Command Design Pattern

Participants: The classes and/or objects participating in this pattern are:

• Command  (e.g. Command) – declares an interface for executing an operation

• ConcreteCommand  (e.g. CalculatorCommand) – defines a binding between a Receiver object and an action – implements Execute by invoking the corresponding operation(s) on Receiver

• Client  (e.g. CommandApp) – creates a ConcreteCommand object and sets its receiver

• Invoker  (e.g. User) – asks the command to carry out the request

• Receiver  (e.g. Calculator) – knows how to perform the operations associated with carrying out the request

Page 27: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

28

Command Design Pattern

Page 28: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

29

Command Design Patternabstract class Command

  {    protected Receiver receiver;

    // Constructor     public Command(Receiver receiver)    {      this.receiver = receiver;    }

    public abstract void Execute();  }

  // "ConcreteCommand"

  class ConcreteCommand : Command  {    // Constructor     public ConcreteCommand(Receiver receiver) :       base(receiver)     {      }

    public override void Execute()    {      receiver.Action();    }  }

  

// "Receiver"

class Receiver   {    public void Action()    {      Console.WriteLine("Called Receiver.Action()");    }  }

  // "Invoker"

  class Invoker   {    private Command command;

    public void SetCommand(Command command)    {      this.command = command;    }

    public void ExecuteCommand()    {      command.Execute();    }    

  }

Page 29: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

30

Command Design Pattern - Client

  class MainApp  {    static void Main()    {      // Create receiver, command, and invoker

      Receiver receiver = new Receiver();      Command command = new ConcreteCommand(receiver);      Invoker invoker = new Invoker();

      // Set and execute command

      invoker.SetCommand(command);      invoker.ExecuteCommand();

      // Wait for user

      Console.Read();    }  }

Output Called Receiver.Action()

Page 30: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

31

Proxy Design Pattern - Operation

• Provide a surrogate or placeholder for another object to control access to it.

• This pattern is useful for situations where object creation is a time consuming process and can make an application appear sluggish. A proxy object can provide the client with feedback while the object is being created.

• Proxy can also be used to provide a more sophisticated reference to an object. For example, the proxy object can implement additional logic on the objects behalf (security, remote procedure calls, an so forth).

Page 31: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

32

Proxy Design PatternParticipants: The classes and/or objects participating in this pattern are:

• Proxy   (MathProxy) – maintains a reference that lets the proxy access the real subject. Proxy may refer to a

Subject if the RealSubject and Subject interfaces are the same. – provides an interface identical to Subject's so that a proxy can be substituted for for the

real subject. – controls access to the real subject and may be responsible for creating and deleting it. – other responsibilites depend on the kind of proxy:

• remote proxies are responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a different address space.

• virtual proxies may cache additional information about the real subject so that they can postpone accessing it. For example, the ImageProxy from the Motivation caches the real images's extent.

• protection proxies check that the caller has the access permissions required to perform a request.

• Subject   (IMath) – defines the common interface for RealSubject and Proxy so that a Proxy can be used

anywhere a RealSubject is expected. • RealSubject   (Math)

– defines the real object that the proxy represents

Page 32: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

33

Proxy Design Pattern

Page 33: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

34

Proxy Design Pattern

// "Subject"

  abstract class Subject   {    public abstract void Request();      }

  // "RealSubject"

  class RealSubject : Subject  {    public override void Request()    {      Console.WriteLine("Called

RealSubject.Request()");    }  }

  // "Proxy"

  class Proxy : Subject  {    RealSubject realSubject;

    public override void Request()    {      // Use 'lazy initialization'       if (realSubject == null)      {        realSubject = new RealSubject();      }

      realSubject.Request();    }    }

Page 34: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

35

Proxy Design Pattern - Client

  class MainApp  {    static void Main()    {      // Create proxy and request a service

      Proxy proxy = new Proxy();      proxy.Request();

      // Wait for user       Console.Read();    }  }

Output Called RealSubject.Request()

Page 35: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

36

Chain of Responsibility Design Pattern

• One of the tenets of software engineering is to keep objects loosely coupled. The Chain of Responsibility is intended to promote loose coupling between the sender of a request and its receiver by giving more than one object an opportunity to handle the request.

• The receiving objects are chained and pass the request along the chain until one of the objects handles it.

• The result is to avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Page 36: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

37

Chain of Responsibility Design Pattern

• Participants: The classes and/or objects participating in this pattern are:

• Handler

– defines an interface for handling the requests – (optional) implements the successor link

• ConcreteHandler – handles requests it is responsible for – can access its successor – if the ConcreteHandler can handle the request, it does so; otherwise it

forwards the request to its successor

• Client– initiates the request to a ConcreteHandler object on the chain

Page 37: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

38

Chain of Responsibility Design Pattern

Page 38: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

39

// "Handler" abstract class Handler { protected Handler successor; public void SetSuccessor(Handler successor)

 {   this.successor = successor; }

 public abstract void HandleRequest(int request);  

}

Chain of Responsibility Design Pattern

// "ConcreteHandler1"

  class ConcreteHandler1 : Handler  {    public override void HandleRequest(int request)    {      if (request >= 0 && request < 10)      {        Console.WriteLine("{0} handled request {1}",           this.GetType().Name, request);      }      else if (successor != null)      {        successor.HandleRequest(request);      }    }  }

Page 39: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

40

// "ConcreteHandler2"

  class ConcreteHandler2 : Handler  {    public override void HandleRequest(int request)    {      if (request >= 10 && request < 20)      {        Console.WriteLine("{0} handled request {1}",           this.GetType().Name, request);      }      else if (successor != null)      {        successor.HandleRequest(request);      }    }  }

Chain of Responsibility Design Pattern

// "ConcreteHandler3"

  class ConcreteHandler3 : Handler  {    public override void HandleRequest(int request)    {      if (request >= 20 && request < 30)      {        Console.WriteLine("{0} handled request {1}",           this.GetType().Name, request);      }      else if (successor != null)      {        successor.HandleRequest(request);      }    }  }

Page 40: 1 ECE 355: Software Engineering CHAPTER 8 Instructor Kostas Kontogiannis

41

class MainApp  {    static void Main()    {      // Setup Chain of Responsibility       Handler h1 = new ConcreteHandler1();      Handler h2 = new ConcreteHandler2();      Handler h3 = new ConcreteHandler3();      h1.SetSuccessor(h2);      h2.SetSuccessor(h3);

      // Generate and process request       int[] requests = {2, 5, 14, 22, 18, 3, 27, 20};

      foreach (int request in requests)      {        h1.HandleRequest(request);      }

      // Wait for user       Console.Read();    }  }

Chain of Responsibility Design Pattern

Output ConcreteHandler1 handled request 2ConcreteHandler1 handled request 5ConcreteHandler2 handled request 14ConcreteHandler3 handled request 22ConcreteHandler2 handled request 18ConcreteHandler1 handled request 3ConcreteHandler3 handled request 27ConcreteHandler3 handled request 20