Software Design Patterns

Florian Rappl, Fakultät für Physik, Universität Regensburg

Software Design Patterns

Introduction to modern software architecture

software architecture

UML

What is the UML?

  • UML means Unified Modeling Language
  • It is a family of graphical notations with a single meta model
  • Purpose: Describe and design software systems
  • In reality it can be used for a lot of things
  • UML is an open standard that is controlled by the OMG (short for Object Management Group)
  • It is used for doing MDA (Model Driven Architecture)

Official logo

UML_logo.gif

  • It was released in 1997, with a major update 2005 (v2.0)
  • The current version of the UML is 2.4.1 (published in August 2011)

UML modes

  • Three modes: sketch, blueprint and programming language
  • UML as a sketch is the most popular
  • Reason: Organization, selectivity, discussion
  • Blueprint diagrams are about completeness
  • They have to be very detailed, such that programmers only need to follow them
  • It is possible that UML represents source code, which can be compiled and executed

UML in practice

  • Four great ways to utilize UML:
    1. Understanding legacy code (e.g. class)
    2. Documentation (e.g. state)
    3. Design (e.g. package)
    4. Requirement analysis (e.g. use-case)
  • UML is a great for communication with non-software people
  • Important here: Keep the notation at a minimum

Diagrams

  • UML 2 has 13 different diagram types
  • The standard indicates that certain elements are typically drawn on certain diagram types
  • But: diagrams are not the central part
  • And one can legally use elements from one diagram in other diagrams
  • Important for us: class, object, activity, use-case and sequence
  • Others: communication, component, composite, deployment, interaction, package, state, timing

Classification of diagrams

Diagram <|-- Structure
Diagram <|-- Behavior
Structure <|- Class
Structure <|--- Composite
Structure <|-- Object
Structure <|-- Component
Structure <|-- Deployment
Structure <|--- Package
Behavior <|-- Activity
Behavior <|-- UseCase
Behavior <|-- StateMachine
Behavior <|--- Interaction
Interaction <|- Sequence
Interaction <|-- Communication
Interaction <|-- Timing
Interaction <|-- Overview

Legal UML

  • Legal UML is how it is set by the standard
  • The problem is the complexity of the specification
  • But: UML is not prescriptive like programming languages
  • Instead the UML is actually a descriptive language
  • Hence the UML is a mix of independent conventions and official notations
  • This results in the UML standard being a guide, not a burden

A sample class diagram

class Order {
  dateReceived: Date [0..1]
  isPrepaid: Boolean [1]
  number: String [1]
  price: Money
  dispatch()
  close()
}
note left: if Order.customer.getCreditRating is "poor"\nthen Order.isPrepaid must be true
class Customer {
  name [1]
  address [0..1]
  getCreditRating(): String
}
class CorporateCustomer {
  contactName
  creditRating
  creditLimit
  billForMonth(Integer)
  remind()
}
class PersonalCustomer {
  creditCardNumber
}
class OrderLine {
  quantity: Integer
  price: Money
}
Order "*" --> "1" Customer
Customer <|-- CorporateCustomer
Customer <|-- PersonalCustomer
CorporateCustomer "*" -> "0..1" Employee
Order "1" --> "*" OrderLine
OrderLine "*" -> "1" Product

Class diagrams

  • Here boxes represent classes
  • The name is on top, usually marked bold
  • Two optional sections: Attributes and operations, with syntax:
    visibility name : type [multiplicity] = default {property}
  • Attributes could be fields or properties (this implies get / set methods)
  • Visibility: + (public), - (private), # (protected) or ~ (package)
  • A name is required, its type is sometimes left out
  • Default value and property (like readonly, frozen, ...) are optional

Relationships

  • Associations are drawn by a solid line ━
  • Such associations can either be uni- (from source to target) or bidirectional (using a simple arrow) ˄
  • Generalization: A solid line that ends with a closed arrow (looks like a triangle) at the general class △
  • Notes or remarks are attached with a dashed line (no arrow required) ┄
  • Dependencies are represented by dashed lines ┈

Aggregation Vs Composition

  • Sometimes we want a special kind of association, either:
    1. Aggregation (opaque rhombus, ◇)
    2. Composition (filled rhombus, ◆)
  • (1) is weak and specifies an optional association, like consisting of
  • (2) is strong and specified a requirement: like is part of
  • Composition also implies a no-sharing rule, i.e. a single class cannot be part of two classes directly, but only of one

Aggregation and Composition

Club "*" o--> "*" Person
Polygon *--> "3..*" Point
Point "1" <--* Circle

Keywords and more

  • We an annotate classes with keywords like «interface» or «abstract»
  • Additionally we can mark static attributes and operations by underlining their definition or using the underscore _ symbol
  • Difference between operation and method: A method is the implementation (body), while an operation represents just the name
  • Some keywords are usually abbreviated (like A for abstract or I for interface)

Generalization

  • Expression of is a relationship: Substitutability
  • Maps directly to inheritance in most OOP languages
  • Subclass/derived class is a generalization of superclass/base class
  • Highest semantically defined relationship
  • The purpose of generalization (inheritance) is to solve design problems
  • Don't use generalization if there is no design problem

Another class diagram

skinparam classAttributeIconSize 0
class Order {
  -done: Boolean [1]
  +dataReceived: Date [0..1]
  +isPrepaid: Boolean [1]
  +lineItems: OrderLine [*] {ordered}
  #owner: Person [1]
  ~deliveryStatus: Delivery [0..1]
}
Person - Order : has > class Set<T> {
  insert(T)
  remove(T)
  {static} instances()
}
EmployeeSet -|> Set : "<<bind>>\n\n<T::Employee>"

Interfaces

  • All operations are public, and no operation has a method body
  • Indicated as keyword «interface», or with a label {interface}, or abbreviated label {I}
  • In this case, inheritance means implementation
  • We can also have a dependency relationship with an interface
  • Additionally ball-and-socket notation very common
  • Ball - class provides interface (labeled), Socket - class requires interface

Example

class Order {
  LineItems [*]
}
interface List {
  get()
}
interface Collection {
  equals()
  add()
}
abstract class AbstractList {
  equals()
  {abstract} get()
  add()
}
class ArrayList {
  get()
  add()
}
Order ..> List
List -|> Collection
AbstractList ..|> List
ArrayList -|> AbstractList

Derived properties

  • Derived properties are attributes
  • They start with a forward slash /
  • In general they represent computed values, i.e. a combination of other attributes (usually there are multiple equal choices)
  • Another name is computed value
  • Very useful to remind people of the underlying constraints

Two examples

class DateRange {
    start: Date
    end: Date
    /length: Integer
}
note right: {length = end - start}

class Order {
  LineItems [*]
}
Order .right.> ArrayList : "using List"
List ()-- ArrayList
Collection ()- ArrayList

Even more notation

  • «struct» for symbolizing value types (should be immutable)
  • «enumeration» for creating an enumeration enum Color {
  red
  blue
  green
}
  • Additionally templates are possible by placing a dashed box in the upper right corner (containing the template parameter(s)) ┊
  • Marking an active class is possible by using two vertical lines ║

Object diagrams

  • Closely related to class diagrams
  • Shows instances at a given time frame
  • Sometimes therefore called instance diagram
  • Usage e.g. showing configuration of objects
  • Names are not in bold, but underlined like Instance : Type
  • Values do not need types and multiplicities (also no methods in general)
  • Values are now mandatory like location = "Boston", or state = false

An object diagram

object "<u>engineering : Organization</u>" as engineering {
  location = "Boston"
}
object "<u>tools : Organization</u>" as tools {
  location = "Chicago"
}
object "<u>apps : Organization</u>" as apps {
  location = "Saba"
}
object "<u>Don : Person</u>" as Don {
  location = "Champaign"
}
object "<u>John : Person</u>" as John {
  location = "Champaign"
}
engineering -- tools : "parent"
engineering -- apps
tools -- Don : "parent"
tools -- John : "parent"

Activity diagrams

  • Technique to describe procedural logic, business process and work flow
  • Quite similar to flowcharts, but they support parallel behavior
  • One new symbol for fork (e.g. 1 in, 2 out) and join (e.g. 2 in, 1 out)
  • Initial node is a filled circle ●
  • Actions are placed in rounded rectangles ▢
  • Decisions are symbolized by rhombi ♢
  • Activity final is represented by a bullseye ◎

Example

start
:Receive Order;
fork
:Send Invoice;
:Receive Payment;
fork again
:Fill Order;
if () then ([Priority Order])
:Overnight Delivery;
else ([else])
:Regular Delivery;
endif
end fork
:Close Order;
stop

Technical remarks

  • Here nodes are called actions, i.e. we have a sequence of actions
  • A decision is called a branch
  • Square brackets contain guards, where else is a special guard that the flow should be used if no other guard applies
  • A merge has to come after a decision (marked by a rhombus), with several incoming and one outgoing flow
  • Additionally one might want to use partitions or even events called signals (which will not be introduced here)

Use Cases

  • Capture the functional requirements of a system
  • An actor is a central node type in such a diagram (sometimes called role)
  • Common information could be added:
    • A pre-condition how the system should look like
    • A guarantee what the outcome is going to be
    • A trigger when to start the use-case
  • Also differentiate between fish-level (only included in higher levels), sea-level (standard) and kite-level (big picture)

Example

:Trading Manager: as TM
:Accounting System: as AS
:Trader: as T
:Salesperson: as S
rectangle boundary {
  (Set Limits) as U1
  (Update Accounts) as U2
  (Analyze Risk) as U3
  (Capture Deal) as U4
  (Price Deal) as U5
  (Value Deal) as U6
  TM --> U1
  AS --> U2
  T --> U3
  T --> U4
  T --> U5
  S --> U4
  S --> U5
  U3 ..> U6 : "<<include>>"
  U5 ..> U6 : "<<include>>"
}

Remarks

  • A use case is a set of scenarios tied together by a common user goal
  • Actors do not need to be human
  • The specification is surprisingly sparse on use cases
  • The value lies completely in the content, not the diagram
  • Usually one starts by writing a use case text
  • Great way for brainstorming alternatives

Sequence diagrams

  • Most important interaction diagram type
  • Captures the behavior of a single scenario
  • Shows example objects and the messages that are passed between these within the scenario (displays no control flow)
  • Objects (□) are bound to lifelines (dashed lines) ┆
  • Messages have a direction →
  • The destruction (delete) of an object is shown with an X
  • Additional annotations like «new» are possible

Example

participant "an Order" as A
participant "an Order Line" as B
participant "aProduct" as C
participant "aCustomer" as D
[-> A: calculatePrice
activate A
A -> B: getQuality
activate B
deactivate B
A -> B: getProduct
activate B
B --> A: aProduct
deactivate B
A -> C: getPricingDetails
activate C
deactivate C
A -> A: calculateBasePrice
activate A
deactivate A
A -> A: calculateDiscounts
activate A
A -> D: getDiscountInfo
activate D
deactivate D
deactivate A
deactivate A

Remarks

  • Common issue: How to show looping? Answer: You don't!
  • If logic is required use an interaction frame, but only in extreme cases
  • Sequence diagrams should illustrate how objects interact
  • Even though deletion is not required in GC environments using the X to indicate disposable objects is worth it
  • Asynchronous messages can also be displayed using the special arrow ⇀

Creation and Deletion

participant "a Handler" as A
participant "a Query Command" as B
participant "a Database Statement" as C
[-> A: query database
activate A
create B
A -> B : new
activate B
create C
B -> C : new
B -> C: execute
activate C
C --> B: results
deactivate C
B -> B: extract results
activate B
deactivate B
B -> C: close
destroy C
deactivate B
B --> A: results
destroy B
deactivate A

Wait...

  • Package diagrams can be used for illustrating top level library views
  • Deployment diagrams are useful for setup or installation processes
  • State machine diagrams supply everything for showing relations between (even concurrent) states
  • Timing diagrams notate timing constraints which is important e.g. for electronic engineering
  • Also communication and (composite) structure diagram types are existing
  • Examples of some types to follow

State Machine diagram

state NotShooting {
  [*] --> Idle
  Idle --> Configuring : EvConfig
  Configuring --> Idle : EvConfig
}

state Configuring {
  [*] --> NewValueSelection
  NewValueSelection --> NewValuePreview : EvNewValue
  NewValuePreview --> NewValueSelection : EvNewValueRejected
  NewValuePreview --> NewValueSelection : EvNewValueSaved
  
  state NewValuePreview {
     State1 -> State2
  }
  
}

Component diagram

package "Some Group" {
  HTTP - [First Component]
  [Another Component]
}
 
node "Other Groups" {
  FTP - [Second Component]
  [First Component] --> FTP
} 

cloud {
  [Example 1]
}


database "MySql" {
  folder "This is my folder" {
    [Folder 3]
  }
  frame "Foo" {
    [Frame 4]
  }
}


[Another Component] --> [Example 1]
[Example 1] --> [Folder 3]
[Folder 3] --> [Frame 4]

Nested classes sample

  • Use a composition arrow (as defined for packages) to indicate nested classes, if really needed
  • Here Enumerator is nested within Dictionary

skinparam classAttributeIconSize 0
class Dictionary<TKey, TValue> {
  +Count: int
  +Add(TKey, TValue): void
  +Remove(TKey): Boolean
  +Has(TKey): Boolean
  +Get(TKey): Value
  +GetEnumerator(): Enumerator
}
class Enumerator {
  +Current: KeyValuePair
  +MoveNext(): Boolean
}

Enumerator +- Dictionary

Common conventions

  • Command-Query separation: Operations with no return value commands, all others are queries (they do not modify anything)
  • If relationships to specific class of objects will change we can mark the relationship in the class diagram with a «temporal» keyword
  • Messages between classes can be drawn using arrows above the relationships with the name of the messages between these classes
  • We can use a rake symbol ⵄ within an action box to indicate a sub activity diagram in an activity diagram

Literature

  • Ambler, Scott William (2004). The Object Primer: Agile Model Driven Development with UML 2.
  • Chonoles, Michael Jesse; James A. Schardt (2003). UML 2 for Dummies.
  • Fowler, Martin (2003). UML Distilled: A Brief Guide to the Standard Object Modeling Language (3rd ed.).
  • Jacobson, Ivar; Booch, Grady; Rumbaugh, James (1998). The Unified Software Development Process.