structural pattern: decorator

18
Structural Pattern: Decorator There are times when the use of subclasses to modify the behavior of individual objects is problematic. Chapter 4 – Page 1 When objects are alike in some fundamental way, but might have a variety of distinctive details, the Decorator Pattern avoids the complexity of having a large number of derived classes. By applying a Decorator class to the base class, and allowing the Decorator class to have the needed derived classes, the base class is kept streamlined, while still affording flexibility when it comes to adding responsibilities to the base class.

Upload: tallys

Post on 23-Feb-2016

57 views

Category:

Documents


0 download

DESCRIPTION

Structural Pattern: Decorator. Chapter 4 – Page 83. There are times when the use of subclasses to modify the behavior of individual objects is problematic. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Structural Pattern: Decorator

Structural Pattern: DecoratorThere are times when the use of subclasses to modify the behavior of individual objects is problematic.

Chapter 4 – Page 1

When objects are alike in some fundamental way, but might have a variety of distinctive details, the Decorator Pattern avoids the complexity of having a large number of derived classes.

By applying a Decorator class to the base class, and allowing the Decorator class to have the needed derived classes, the base class is kept streamlined, while still affording flexibility when it comes to adding responsibilities to the base class.

Page 2: Structural Pattern: Decorator

The Decorator PatternChapter 4 – Page 2The Component defines the interface for objects that can have responsibilities added to them dynamically.The ConcreteComponent defines an object to which additional responsibilities can be attached. The Decorator maintains a reference to a Component object and defines an interface that conforms to the Component’s interface.Each ConcreteDecorator adds responsibilities to the Component.

ConcreteComponent

Operation()

ConcreteDecoratorAAddedState

Operation()

ConcreteDecoratorB

Operation()AddedBehavior()

Decorator

Operation()

Component

Operation()

+component

Operation() component.Operation()

Operation() base.Operation(); AddedBehavior();

Page 3: Structural Pattern: Decorator

Non-Software Decorator ExampleThe abstract LibraryItem component has two derived classes: the concrete Book component and the concrete Video component.

Chapter 4 – Page 3

The abstract Decorator class has one derived class: the concrete Borrowable Decorator, which extends the LibraryItem by adding and maintaining a list of borrowers.Regular books and videos have their appropriate attributes, but also have a list of borrowers when decorated as Borrowable.

VideoDirectorTitlePlayTime

Display()

BorrowableBorrowers[]

Display()BorrowItem()ReturnItem()

Decorator

Display()

LibraryItemNumberOfCopies

Display()

BookAuthorTitle

Display()

Page 4: Structural Pattern: Decorator

Software Decorator ExampleThe AbstractCheckIn component has a derived class: the concrete ActualCheckIn component.

Chapter 4 – Page 4

The abstract CheckInDecorator class has three derived concrete Decorator subclasses: the AccessibilityCheckIn (for blindness and wheelchairs), the CommunicationCheckIn (for broadband and Internet access), and the FamilyCheckIn (for family size).

ActualCheckIn

GetSuitableRooms()

AccessibilityCheckInAccessibilityNeeds

GetSuitableRooms()

CommunicationCheckInCommunicationNeeds

GetSuitableRooms()

AbstractCheck In

GetSuitableRooms()

CheckInDecorator

GetSuitableRooms()

FamilyCheckInFamilySize

GetSuitableRooms()

Page 5: Structural Pattern: Decorator

Check-In Decorator Pattern VB CodeChapter 4 – Page 5

Special Needs FormAppears to provide opportunity to input special needs of guests.

Suitable Accommodation

FormAppears to provide

list of potential lodgings that meet

guest’s special needs.

Page 6: Structural Pattern: Decorator

Chapter 4 – Page 6

Public Class frmSpecialNeeds Inherits System.Windows.Forms.Form

Dim FullyDecoratedCheckIn As AbstractCheckIn Dim dvSuitableRooms As DataView

'This is a test value. Normally this value would have 'been passed to this form from some other form Dim GuestDetails As String = "G120"

Private Sub btnGetSuitableRooms_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnGetSuitableRooms.Click

FullyDecoratedCheckIn = GetDecorators() Dim PreDecorator As New PreDecorationObject dvSuitableRooms = FullyDecoratedCheckIn.GetSuitableRooms(PreDecorator)

Dim SuitableAccomodationsForm As New frmSuitableAccomodation SuitableAccomodationsForm.GuestBookableRooms = dvSuitableRooms SuitableAccomodationsForm.GuestNumberToCheckIn = GuestDetails SuitableAccomodationsForm.Show() End Sub

Public Function GetDecorators() As AbstractCheckIn Dim FullyDecoratedCheckIn As AbstractCheckIn

Dim AccessibilityRequirements As String = "" Dim CommunicationNeeds As String = "" Dim FamilySize As String = ""

Dim CheckInDecoratorFactory As New DecoratorFactory Dim CheckInToDecorate As AbstractCheckIn = New ActualCheckIn

Code for the Special Needs Form

Page 7: Structural Pattern: Decorator

Chapter 4 – Page 7 For Each AccessibilityChoice As CheckBox In Me.gbxAccessibility.Controls If AccessibilityChoice.Checked Then If AccessibilityRequirements <> "" Then AccessibilityRequirements &= " , " End If AccessibilityRequirements &= AccessibilityChoice.Text End If Next

For Each ChildrenChoiceNo As RadioButton In Me.gbxChildren.Controls If ChildrenChoiceNo.Checked Then FamilySize = ChildrenChoiceNo.Text Exit For End If Next

For Each CommunicationChoice As RadioButton In Me.gbxCommunications.Controls If CommunicationChoice.Checked Then CommunicationNeeds = CommunicationChoice.Text Exit For End If Next

Dim RequirementsArray() As String = _ {AccessibilityRequirements, CommunicationNeeds, FamilySize}

FullyDecoratedCheckIn = CheckInDecoratorFactory.GetFullyDecoratedCheckin(CheckInToDecorate, RequirementsArray) Return FullyDecoratedCheckIn

End Function

Private Sub frmSpecialNeeds_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.txtGuestDetails.Text = Me.GuestDetails End SubEnd Class

Page 8: Structural Pattern: Decorator

Chapter 4 – Page 8

Imports System.Data.OleDb

Public Class frmSuitableAccomodation Inherits System.Windows.Forms.Form

Public GuestNumberToCheckIn As String Public GuestBookableRooms As DataView

Private Sub btnCheckInGuest_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCheckInGuest.Click ' Logic for inserting the Guest number passed to the form into the database ' as the guest who should be assigned to the room which is checked

End Sub

Private Sub frmSuitableAccomodation_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load

Me.dgrGuestsAndRooms.DataSource = Me.GuestBookableRooms

End SubEnd Class

Code for the Accommodation Form

Page 9: Structural Pattern: Decorator

Chapter 4 – Page 9Public Class DecoratorFactory

'This is a sort of "Decorator-Factory", calling in the 'functions in order of inner-decorator to outer-decorator. Public PartiallyDecoratedCheckin As AbstractCheckIn

Public AccessibilityGroupBox As GroupBox Public CommunicationsGroupBox As GroupBox Public childrenGroupBox As GroupBox

Public Function GetFullyDecoratedCheckin(ByVal UndecoratedCheckin As AbstractCheckIn, _ ByVal DecorationParameters() As String) As AbstractCheckIn Dim FullyDecoratedCheckin As AbstractCheckIn

' This is where we decide the order in which to wrap the decorators. If the order is very ' important, then we brainstorm with the subject experts once, figure out how to wrap ' them once, decide once and all clients which call the factory will benefit from the ' stantardized decisions we have made so the possibility of getting it wrong is reduced.

PartiallyDecoratedCheckin = _ GetAccessibilityDecorator(UndecoratedCheckin, DecorationParameters(0)) PartiallyDecoratedCheckin = _ GetCommunicationDecorator(PartiallyDecoratedCheckin, DecorationParameters(1)) FullyDecoratedCheckin = _ GetFamilyDecorator(PartiallyDecoratedCheckin, DecorationParameters(2))

Return FullyDecoratedCheckin End Function

Code for the “Decorator Factory”

Page 10: Structural Pattern: Decorator

Chapter 4 – Page 10 Private Function GetAccessibilityDecorator(ByVal ComponentToDecorate As AbstractCheckIn, _ ByVal AccessibilityString As String) As AbstractCheckIn

Dim DecoratoredCheckIn As AbstractCheckIn

If AccessibilityString <> "" Then DecoratoredCheckIn = _ New AccessibilityRequirementsDecorator(ComponentToDecorate, AccessibilityString) Else DecoratoredCheckIn = ComponentToDecorate ' We return the object undecorated End If Return DecoratoredCheckIn

End Function

Private Function GetFamilyDecorator(ByVal ComponentToDecorate As AbstractCheckIn, _ ByVal FamilyString As String) As AbstractCheckIn

Dim DecoratoredCheckIn As AbstractCheckIn

'The following if statement decides whether to wrap the component which was passed to the ' function (which may itself be a component or a decorated component) in a decorator ' and pass it back, or simply return the undecorated parameter back to the caller. If FamilyString <> "None" Then DecoratoredCheckIn = New FamilyRequirementsDecorator(ComponentToDecorate, FamilyString) Else DecoratoredCheckIn = ComponentToDecorate ' We return the object undecorated End If Return DecoratoredCheckIn

End Function

Page 11: Structural Pattern: Decorator

Chapter 4 – Page 11 Private Function GetCommunicationDecorator(ByVal ComponentToDecorate As AbstractCheckIn, _ ByVal CommunicationString As String) As AbstractCheckIn

Dim DecoratoredCheckIn As AbstractCheckIn

If CommunicationString <> "None" Then DecoratoredCheckIn = _ New CommunicationRequirementsDecorator(ComponentToDecorate, CommunicationString) Else DecoratoredCheckIn = ComponentToDecorate ' We return the object undecorated End If Return DecoratoredCheckIn

End FunctionEnd Class

Page 12: Structural Pattern: Decorator

Chapter 4 – Page 12Imports System.Data.OleDb

Public Interface AbstractCheckIn ' Abstract Component Function GetSuitableRooms(ByVal DecorationObject As PreDecorationObject) As DataView

End Interface

Public Class ActualCheckIn ' Concrete Component Implements AbstractCheckIn

Public Function GetSuitableRooms(ByVal DecorationObject As PreDecorationObject) _ As DataView Implements AbstractCheckIn.GetSuitableRooms

Dim strRoomsConnection As String 'Note: Ensure that the database path and name used in this connection string are correct. strRoomsConnection = _ "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source=C:\Decorator_CheckIn.Mdb" Dim connRooms As New OleDbConnection(strRoomsConnection) connRooms.Open()

Dim strRoomsSQL As String = "Select * from rooms " Dim strSQLExtension As String = DecorationObject.WhereClause Dim cmdRooms As New OleDbCommand(strRoomsSQL & strSQLExtension, connRooms) Dim daRooms As New OleDbDataAdapter(cmdRooms) Dim dtRooms As New DataTable daRooms.Fill(dtRooms) Dim dvRooms As New DataView(dtRooms) Return dvRooms

End Function

End Class

Decorator and Component Code

Page 13: Structural Pattern: Decorator

Chapter 4 – Page 13Public Class CheckInDecorator ' Abstract Decorator Implements AbstractCheckIn

'Because it holds a reference to an abstract class, it doesn't know until ' runtime whether it is another decorator like itself or a concrete ' component. This allows for recursive composure to any depth required.

Private m_ActualCheckIn As AbstractCheckIn

Private Sub New() End Sub

Public Sub New(ByVal CheckIn As AbstractCheckIn) m_ActualCheckIn = CheckIn End Sub

Public ReadOnly Property ActualCheckin() As AbstractCheckIn Get Return m_ActualCheckIn End Get End Property

Public Overridable Function GetSuitableRooms(ByVal DecorationObject As PreDecorationObject) _ As DataView Implements AbstractCheckIn.GetSuitableRooms

End FunctionEnd Class

Page 14: Structural Pattern: Decorator

Chapter 4 – Page 14

Public Class AccessibilityRequirementsDecorator Inherits CheckInDecorator

Dim AccessibilityNeeds As String

Public Sub New(ByVal CheckOp As AbstractCheckIn, ByVal AccessNeeds As String) MyBase.new(CheckOp) AccessibilityNeeds = AccessNeeds End Sub

Public Overrides Function GetSuitableRooms(ByVal DecorationObject _ As PreDecorationObject) As DataView

' On the way in, intercept the SQLs and finetune them more If DecorationObject.WhereClause = "" Then DecorationObject.WhereClause += " where “ Else DecorationObject.WhereClause += " and “ End If DecorationObject.WhereClause += " ExitRoom = 'True'"

' On the way back out, intercept the dataset and make it ' more useful by sorting on the Accessibility issues Dim FinalDataView As DataView = Me.ActualCheckin.GetSuitableRooms(DecorationObject) FinalDataView.Sort = AccessibilityNeeds Return FinalDataView

End Function

End Class

Page 15: Structural Pattern: Decorator

Chapter 4 – Page 15Public Class CommunicationRequirementsDecorator Inherits CheckInDecorator

Dim CommunicationNeeds As String

Public Sub New(ByVal CheckOp As AbstractCheckIn, ByVal CommNeeds As String) MyBase.new(CheckOp) CommunicationNeeds = CommNeeds End Sub

Public Overrides Function GetSuitableRooms(ByVal DecorationObject _ As PreDecorationObject) As DataView

If DecorationObject.WhereClause = "" Then DecorationObject.WhereClause += " where " Else DecorationObject.WhereClause += " and " End If DecorationObject.WhereClause += " CommunicationsSetup = '" & CommunicationNeeds & "'"

Return Me.ActualCheckin.GetSuitableRooms(DecorationObject)

End FunctionEnd Class

Page 16: Structural Pattern: Decorator

Chapter 4 – Page 16Public Class FamilyRequirementsDecorator ' Concrete Decorator Inherits CheckInDecorator

Dim NumberofChildren As Integer

Public Sub New(ByVal CheckOp As AbstractCheckIn, ByVal NumberChildrenInWords As String) MyBase.new(CheckOp) NumberofChildren = ConvertFromStringToNumber(NumberChildrenInWords) End Sub

Function ConvertFromStringToNumber(ByVal NumberAsWords As String) As Integer Select Case LCase(NumberofChildren) Case "one" NumberofChildren = 1 Case "one" NumberofChildren = 2 End Select

End Function

Public Overrides Function GetSuitableRooms(ByVal DecorationObject _ As PreDecorationObject) As DataView

Select Case Me.NumberofChildren Case 1 DecorationObject.WhereClause += " and ChildAmenities = 'Medium'" Case 2 DecorationObject.WhereClause += " and ChildAmenities = 'High'" End Select

Return Me.ActualCheckin.GetSuitableRooms(DecorationObject)

End FunctionEnd Class

Page 17: Structural Pattern: Decorator

Chapter 4 – Page 17

Public Class PreDecorationObject Public ColumnsClause As String Public WhereClause As String

Public Sub New() Me.ColumnsClause = "" Me.WhereClause = "" End Sub

End Class

Page 18: Structural Pattern: Decorator

Decorator Pattern AdvantagesChapter 4 – Page 18

• The Decorator Pattern provides a more flexible way to add responsibilities to a class than the use of inheritance, since it can add these responsibilities to selected instances of the class.

• One disadvantage of this pattern is that the Decorator and its enclosed Component are not identical, so tests for object type will fail.

• The Decorator Pattern also allows you to customize a class without creating subclasses high in the inheritance hierarchy.

• Another problem is that this pattern tends to produce a system with several very similar objects, which can lead to confusion for the programmer maintaining the code.