Home > Sample chapters > Programming > C#

F# and Design Patterns for C# Developers

Working with F# and Design Patterns

Let’s start by looking at some of the design patterns that will be discussed in this chapter along with the definitions of each. Note that the following definitions are from an OOP perspective, so the definitions occasionally still use object-oriented terminology:

  • The chain of responsibility pattern avoids coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. It chains the receiving objects and passes the request along the chain until an object handles it.

  • The decorator pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

  • The observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

  • The proxy pattern provides a surrogate or placeholder for another object to control access to it.

  • The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. This pattern lets the algorithm vary independently from clients that use it.

  • The state pattern allows an object to alter its behavior when its internal state changes.

  • The factory pattern lets a class defer instantiation to subclasses.

  • The adapter pattern and bridge pattern are both used to convert the interface of a class into another interface. The adapter pattern lets classes work together that couldn’t otherwise because of incompatible interfaces. If we don’t focus on interfaces or classes, we can rephrase the definition to a shorter one: These are patterns that provide a way to allow incompatible types to interact.

  • The singleton pattern ensures a class has only one instance and provides a global point of access to it.

  • The command pattern is used to allow an object to store the information needed to execute some other functionality at a later time. For example it can help implement a redo-undo scenario.

  • The composite pattern describes a group of objects that are to be treated in the same way as a single instance of an object. The intent of a composite is to compose objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly. The visitor pattern separates the algorithm implementation from the data structure. These two patterns can work together. The composite pattern forms a tree structure, and the visitor pattern applies a function to the tree structure and brings the result back.

  • The template pattern is, as its name suggests, a program or algorithm skeleton.

  • The private data class pattern is used to encapsulate fields and methods that can be used to manipulate the class instance.

  • The builder pattern provides abstract steps of building objects. Using this pattern allows a developer to pass different implementations of abstract steps.

  • The façade pattern allows you to create a higher level interface that can be used to make it easier to invoke underlying class libraries.

  • The memento pattern saves an object’s internal state for later use.

Working with the Chain of Responsibility Pattern

The chain of responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains a set of logic that describes the types of command objects it can handle and how to pass off those it cannot handle to the next processing object in the chain. The sample in Listing 3-2 shows a physical check process that needs to make sure that a person’s age is between 18 and 65, that their weight is no more than 200 kilograms, and that they are taller than 120 centimeters.

The type in Listing 3-2 is called a Record. Listing 3-2 uses a Record to store a patient’s medical data. It has several named fields that are used to hold the patient’s data. It is very much like a database record. Listing 3-1 shows how to define a Record type and create a record object. The sample code creates a point record that has its X and Y fields set to (1, 1).

Listing 3-1 Defining a record type and creating a Record object

// define a point record
type Point2D = {
    X : float
    Y : float
}

// create original point record
let originalPoint = { X = 0.0; Y = 0.0 }

// create (1,1) point record
let onePoint = { X = 1.0; Y = 1.0 }

The record object implicitly forces data initialization; therefore, initial values are not optional when creating a Record type. The invoker must define the patient with some data, and this eliminates any possible initialization problems.

Listing 3-2 Chain of responsibility pattern

// define a record to hold a person's age and weight
type Record = {
    Name : string;
    Age : int
    Weight: float
    Height: float
}

// Chain of responsibility pattern
let chainOfResponsibility() =

    // function to check that the age is between 18 and 65
    let validAge record =
        record.Age < 65 && record.Age > 18

    // function to check that the weight is less than 200
    let validWeight record =
        record.Weight < 200.

    // function to check that the height is greater than 120
    let validHeight record =
        record.Height > 120.

    // function to perform the check according to parameter f
    let check f (record, result) =
        if not result then record, false
        else record, f(record)

    // create chain function
    let chainOfResponsibility = check validAge >> check validWeight >> check validHeight

    // define two patients' records
    let john = { Name = "John"; Age = 80; Weight = 180.; Height = 180. }
    let dan = { Name = "Dan"; Age = 20; Weight = 160.; Height = 190. }

    printfn "John's result = %b" (chainOfResponsibility (john, true) |> snd)
    printfn "Dan's result = %b" (chainOfResponsibility (dan, true) |> snd)

Execution result from the chain of responsibility sample

John's result = false
Dan's result = true

In the implementation in Listing 3-2, three functions (responsibilities) are composed into a chain and the data is passed along the chain when it is being processed. The parameter passed in contains a Boolean variable that decides whether the data can be processed. In Listing 3-2, all the functions are in effect AND-ed together. The parameter passed into the first function contains a Boolean value. The successive function can be invoked only if the Boolean value is true.

The other implementation is used for pipelining, as shown in Listing 3-3, rather than function composition. The chainTemplate higher-order function takes a process and canContinue function. The canContinue function always returns true, and the process function is a simple “increase one” function. The execution result is 2.

Listing 3-3 Chain of responsibility sample using pipelining

// chain template function
let chainTemplate processFunction canContinue s =
    if canContinue s then
        processFunction s
    else s

let canContinueF _ = true
let processF x = x + 1

//combine two functions to get a chainFunction
let chainFunction = chainTemplate processF canContinueF

// use pipeline to form a chain
let s = 1 |> chainFunction |> chainFunction

printfn "%A" s

The other chain of responsibility implementation uses the partial pattern feature in F#. I introduced the unit of measure to make the code readable. The process goes from the first case and stops when the condition is met. The sample code is listed in Listing 3-2. The sample code checks the height and weight value for some predefined criteria. The person’s data is checked against NotPassHeight and then NotPassWeight if his height passes the validation criteria. The code also demonstrates how to use the F# unit-of-measure feature, which avoids possible confusion because of the unit of measure used. The parameter for makeCheck is #Person, which means that any object of type Person or derived from a Person type can be passed in.

Listing 3-4 uses units-of-measure language constructs within a calculation. Only the number with the same unit of measure can be involved in the same calculation. Listing 3-4 shows how to define a kilogram (kg) unit and decorate it with a number.

Listing 3-4 Defining and using a kg unit of measure

// define unit-of-measure kg
[<Measure>] type kg

// define 1kg and 2kg variables
let oneKilo = 1<kg>
let twoKilo = 1<kg> + 1<kg>

The None and Some(person) syntax in the sample code in Listing 3-6 represents a Nullable-type-like data structure called an option. You can think of None as NULL. The special function let (| NotPassHeight | _ |) is called an active pattern. It takes a person parameter and decides whether the person meets certain criteria. If the person meets the criteria, the function returns Some(person) and triggers the match statement. Listing 3-5 shows how to use the Some()/None syntax to check for an odd number. This sample introduced several new concepts. I will come back to these concepts in detail in Chapter 5.

Listing 3-5 Using active pattern, option, and match to check for an odd number

// define an active pattern function to check for an odd number
let (| Odd | _ |) x = if x % 2 = 0 then None else Some(x)

// define a function to check for an odd number
let findOdd x =
    match x with
    | Odd x -> printfn "x is odd number"
    | _ -> printfn "x is not odd number"

// check odd number
findOdd 3
findOdd 4

Execution result

x is odd number
x is not odd number

Listing 3-6 Chain of responsibility pattern using partial pattern matching

// define two units of measure: cm and kg
[<Measure>] type cm
[<Measure>] type kg

// define a person class with its height and weight set to 0cm and 0kg
type Person() =
    member val Height = 0.<cm> with get, set
    member val Weight = 0.<kg> with get, set

// define a higher order function that takes a person record as a parameter
let makeCheck passingCriterion (person: #Person) =
    if passingCriterion person then None  //if passing, say nothing, just let it pass
    else Some(person)   //if not passing, return Some(person)

// define NotPassHeight when the height does not meet 170cm
let (| NotPassHeight | _ |) person = makeCheck (fun p -> p.Height > 170.<cm>) person

// define the NotPassWeight when weight does not fall into 100kg and 50kg range
let (| NotPassWeight | _ |) person =
    makeCheck (fun p -> p.Weight < 100.<kg> && p.Weight > 50.<kg>) person

// check incoming variable x
let check x =
    match x with
    | NotPassHeight x -> printfn "this person is not tall enough"
    | NotPassWeight x -> printfn "this person is out of weight range"
    | _ -> printfn "good, this person passes"

// create a person with 180cm and 75kg
let p = Person(Height = 180.<cm>, Weight = 75.<kg>)

// perform the chain check
check p

Execution result

good, this person passes

Working with the Adapter Pattern

The adapter pattern is a design pattern that translates one interface for a type into an interface that is compatible with some other type. An adapter allows classes to work together that normally could not because of incompatible types. In Listing 3-8, we use the Generic Invoke(GI) function as an adapter or bridge to invoke two methods of incompatible types. By using the GI function, a common interface is no longer needed and the function can still be invoked. The GI function is a static type constraint function, it requires that type T define a certain member function. For example, in Listing 3-7, it requires that the type T has a canConnect function that takes void (unit) and returns a Boolean. (Note that F# requires you to declare a function as “inline” when arguments of the function are statically resolved type parameters such as those in the following code listing.)

Listing 3-7 GI function

// define a GI function
let inline canConnect (x : ^T) = (^T : (member CanConnect : unit->bool) x)

The interesting thing about the design pattern implementation in Listing 3-8 is that Cat and Dog do not have any common base class or interface. However, they can still be processed in a unified function. This implementation can be used to invoke the legacy code, which does not share any common interface or base class. (You should note, by the way, that this is a sloppy way of solving the problem and should be considered only when no other option is available.)

Imagine that you have two legacy systems that need to be integrated and that you do not have access to the source code. It would be difficult to integrate the systems in other languages, but it’s possible and even easy in F# using the generic invoke technique.

Listing 3-8 The adapter pattern (bridge pattern)

//define a cat class
type Cat() =
    member this.Walk() = printfn "cat walks"

// define a dog class
type Dog() =
    member this.Walk() = printfn "dog walks"

// adapter pattern
let adapterExample() =
    let cat = Cat()
    let dog = Dog()

    // define the GI function to invoke the Walk function
    let inline walk (x : ^T) = (^T : (member Walk : unit->unit) x)

    // invoke GI and both Cat and Dog
    walk(cat)
    walk(dog)

Execution result from adapter pattern sample

cat walks
dog walks

Working with the Command Pattern

The command pattern is a design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. Listing 3-10 shows how to use the command pattern to implement a redo-undo framework. This is an example of typical usage of the command pattern in the OOP world.

Listing 3-9 defines a result using the ref keyword. The ref keyword defines a reference type that points to the value 7. The result is a reference cell. You can think of the ref keyword as a way to define a mutable variable.

Listing 3-9 Reference cell

// define a reference cell to value 0
let a = ref 0

// define a function to increase a's value by 1
let increaseA() =
    a := !a + 1

// increase a's value and print out result
increaseA()
printfn "a = %A" !a

Execution result

a = 1

Listing 3-10 Command pattern

// define a command record
type Command = { Redo: unit->unit; Undo: unit->unit }

let commandPatternSample() =

    // define a mutable storage
    let result = ref 7

    // define the add command
    let add n = {
        Redo = (fun _ -> result := !result + n)
        Undo = (fun _ -> result := !result - n) }

    // define the minus command
    let minus n = {
        Redo = (fun _ -> result := !result - n)
        Undo = (fun _ -> result := !result + n) }

    // define an add 3 command
    let cmd = add 3
    printfn "current state = %d" !result

    // perform add 3 redo operation
    cmd.Redo()
    printfn "after redo: %d" !result

    // perform an undo operation
    cmd.Undo()
    printfn "after undo: %d" !result

Execution result from the command pattern sample obtained by invoking the commandPatternSample function

current state = 7
after redo: 10
after undo: 7

There is another implementation that emphasizes that the command can be treated like data. The code defines two types of commands: deposit and withdraw. The Do and Undo functions are used to perform the do and undo actions. See Listing 3-12.

To implement this Do and Undo functionality, it is helpful to understand the F# discriminated union (DU) feature. Listing 3-11 demonstrates how to use a DU to check whether or not the given time is a working hour. Note how the first DU, DayOfAWeek, looks a lot like an enum, but without the default numeric value. In the second example, TWorkingHour, the DU case Hour has a tuple value, where the first element of the tuple is a DayOfAWeek and the second element is an integer.

Listing 3-11 Using DU to check whether the given time is a working hour

// define day of the week
type DayOfAWeek =
    | Sunday
    | Monday
    | Tuesday
    | Wednesday
    | Thursday
    | Friday
    | Saturday

// define working hour
type TWorkingHour =
    | Hour of DayOfAWeek * int

// check that the working hour is Monday to Friday 9:00 to 17:00
let isWorkingHour day =
    match day with
    | Hour(Sunday, _) -> false
    | Hour(Saturday, _) -> false
    | Hour(_, time) -> time >= 9 && time <= 17

// check if Sunday is working hour
let sunday = Hour(Sunday, 9)
printfn "%A is working hour? %A" sunday (isWorkingHour sunday)

// check if Monday 10:00 is working hour
let monday = Hour(Monday, 10)
printfn "%A is working hour? %A" monday (isWorkingHour monday)

Execution result

Hour (Sunday,9) is working hour? false
Hour (Monday,10) is working hour? true

Now that you understand discriminated unions, you can apply them to the command pattern.

Listing 3-12 Command pattern implementation II

// define two command types
type CommandType =
    | Deposit
    | Withdraw

// define the command format, which has a command type and an integer
type TCommand =
    | Command of CommandType * int

// mutable variable result
let result = ref 7

// define a deposit function
let deposit x = result := !result + x

// define a withdraw function
let withdraw x = result := !result - x

// do function to perform a do action based on command type
let Do = fun cmd ->
    match cmd with
    | Command(CommandType.Deposit, n) -> deposit n
    | Command(CommandType.Withdraw,n) -> withdraw n

// undo function to perform an undo action based on command type
let Undo = fun cmd ->
    match cmd with
    | Command(CommandType.Deposit, n) -> withdraw n
    | Command(CommandType.Withdraw,n) -> deposit n

// print the current balance
printfn "current balance %d" !result

// deposit 3 into the account and print the balance
let depositCmd = Command(Deposit, 3)
Do depositCmd
printfn "after deposit: %d" !result

// undo the deposit command and print the balance
Undo depositCmd
printfn "after undo: %d" !result

Execution result

current balance 7
after deposit: 10
after undo: 7

Working with the Observer Pattern

The observer pattern is a pattern in which a subject object maintains a list of its observer dependents. The subject automatically notifies its dependents of any changes by calling one of the dependent’s methods. The implementation in Listing 3-13 passes the function into the subject, and the subject notifies its changes by calling this function along with some parameters.

Listing 3-13 Observer pattern

// define a subject
type Subject() =
    // define a default notify function
    let mutable notify = fun _ -> ()

    // subscribe to a notification function
    member this.Subscribe notifyFunction =
        let wrap f i = f i; i
        notify <- wrap notifyFunction >> notify

    // reset notification function
    member this.Reset() = notify <- fun _ -> ()

    // notify when something happens
    member this.SomethingHappen k =
        notify k

// define observer A
type ObserverA() =
    member this.NotifyMe i = printfn "notified A %A" i

// define observer B
type ObserverB() =
    member this.NotifyMeB i = printfn "notified B %A" i

// observer pattern
let observer() =
    // create two observers
    let a = ObserverA()
    let b = ObserverB()

    // create a subject
    let subject = Subject()

    // let observer subscribe to subject
    subject.Subscribe a.NotifyMe
    subject.Subscribe b.NotifyMeB

    // something happens to the subject
    subject.SomethingHappen "good"

Execution result from the observer pattern sample obtained by invoking the observer function

notified B "good"
notified A "good"

F#’s Observable module can be used to implement this pattern as well. In Listing 3-14, an event is defined along with three observers of the event. Compared to the version in Listing 3-13, this version is much more lightweight. The myEvent value is bound to an instance of the F# event type. For the Observable module to subscribe to the event, you have to publish the event. After the event is published, the Observable.add function is used to add the event-handler function to this event. When the event is fired by using Trigger, all the event-handler functions will be notified.

Listing 3-14 Using the Observable module to implement the observer pattern

// define an event
let myEvent = Event<_>()

// define three observers
let observerA = fun i -> printfn "observer A noticed something, its value is %A" i
let observerB = fun i -> printfn "observer B noticed something, its value is %A" i
let observerC = fun i -> printfn "observer C noticed something, its value is %A" i

// publish the event and add observerA
myEvent.Publish
|> Observable.add observerA

// publish the event and add observerA
myEvent.Publish
|> Observable.add observerB

// publish the event and add observerA
myEvent.Publish
|> Observable.add observerC

//fire event with value 1
myEvent.Trigger 1

Execution result

observer A noticed something, its value is 1
observer B noticed something, its value is 1
observer C noticed something, its value is 1

Working with the Decorator Pattern

The decorator pattern can be used to extend (a.k.a. decorate) the functionality of an object at run-time. In Listing 3-15, the decorator pattern is used along with the composite operator to add new logic to the existing function. As the function is passed dynamically into a structure, the run-time behavior can be easily changed. The sample code defines a property that exposes a function. This function can then be changed at runtime.

Listing 3-15 Decorator pattern

// define the Divide class
type Divide() =
    // define basic divide function
    let mutable divide = fun (a,b) -> a / b

    // define a property to expose the function
    member this.Function
        with get() = divide
        and set(v) = divide <- v

    // method to invoke the function
    member this.Invoke(a,b) = divide (a,b)

// decorator pattern
let decorate() =

    // create a divide instance
    let d = Divide()

    // set the check zero function
    let checkZero (a,b) = if b = 0 then failwith "a/b and b is 0" else (a,b)

    // invoke the function without check zero
    try
        d.Invoke(1, 0) |> ignore
    with e -> printfn "without check, the error is = %s" e.Message

    // add the check zero function and then invoke the divide instance
    d.Function <- checkZero >> d.Function
    try
        d.Invoke(1, 0) |> ignore
    with e -> printfn "after add check, error is = %s" e.Message

Execution result from the decorator pattern sample obtained by invoking the decorate function

without check, the error is = Attempted to divide by zero.
after add check, error is = a/b and b is 0

Working with the Proxy Pattern

The proxy pattern uses a class that acts as a placeholder or interface for another object or function. It’s often used for caching, to control access, or to delay the execution or creation of an object that is costly in the form of time or resources. See Listing 3-16. The CoreComputation class hosts two calculation functions, named Add and Sub. The class also exposes a proxy class from which a user can get access to the computation.

Listing 3-16 Proxy pattern

// define core computation
type CoreComputation() =
    member this.Add(x) = x + 1
    member this.Sub(x) = x - 1
    member this.GetProxy name =
        match name with
        | "Add" -> this.Add, "add"
        | "Sub" -> this.Sub, "sub"
        | _ -> failwith "not supported"

// proxy implementation
let proxy() =
    let core = CoreComputation()

    // get the proxy for the add function
    let proxy = core.GetProxy "Add"

    // get the compute from proxy
    let coreFunction = fst proxy

    // get the core function name
    let coreFunctionName = snd proxy

    // perform the core function calculation
    printfn "performed calculation %s and get result = %A" coreFunctionName (coreFunction 1)

Execution result from the proxy pattern sample obtained by invoking the proxy function

performed calculation add and get result = 2

Working with the Strategy Pattern

The strategy pattern is a software design pattern whereby algorithms can be selected and used at runtime. Listing 3-17 uses a function to hold different strategies. During runtime, the strategy can be modified.

Listing 3-17 Strategy pattern

// quick sort algorithm
let quicksort l =
    printfn "quick sort"

// shell short algorithm
let shellsort l =
    printfn "shell short"

// bubble short algorithm
let bubblesort l =
    printfn "bubble sort"

// define the strategy class
type Strategy() =
    let mutable sortFunction = fun _ -> ()
    member this.SetStrategy f = sortFunction <- f
    member this.Execute n = sortFunction n

let strategy() =
    let s = Strategy()

    // set strategy to be quick sort
    s.SetStrategy quicksort
    s.Execute [1..6]

    // set strategy to be bubble sort
    s.SetStrategy bubblesort
    s.Execute [1..6]

Execution result from the strategy pattern sample obtained by invoking the strategy function

quick sort
bubble sort

Listing 3-17 shows how to implement this pattern using the OOP paradigm. However, the strategy pattern can be implemented more succinctly with a functional approach. Listing 3-18 shows how to use the higher-order function named executeStrategy to implement this pattern using a functional paradigm.

Listing 3-18 Strategy pattern using a higher-order function

// quick sort algorithm
let quicksort l =
    printfn "quick sort"

// shell short algorithm
let shellsort l =
    printfn "shell short"

// bubble short algorithm
let bubblesort l =
    printfn "bubble sort"

let executeStrategy f n = f n

let strategy() =
    // set strategy to be quick sort
    let s = executeStrategy quicksort
    // execute the strategy against a list of integers
    [1..6] |> s

    // set strategy to be bubble sort
    let s2 = executeStrategy bubblesort
    // execute the strategy against a list of integers
    [1..6] |> s2

Working with the State Pattern

The state pattern is used to represent the ability to vary the behavior of a routine depending on the state of an object. This is a clean way for an object to partially change its type at runtime. Listing 3-19 shows that the interest rate is decided by the internal state: account balance. The higher the balance is, the higher the interest is that a customer will receive. In the sample, I also demonstrate how to use the unit-of-measure feature.

Listing 3-19 State pattern

// define account state
type AccountState =
    | Overdrawn
    | Silver
    | Gold

// define unit of measure as US dollar
[<Measure>] type USD

// define an account that takes the unit of measure
type Account<[<Measure>] 'u>() =
    // field to hold the account balance
    let mutable balance = 0.0<_>

    // property for account state
    member this.State
        with get() =
            match balance with
            | _ when balance <= 0.0<_> -> Overdrawn
            | _ when balance > 0.0<_> && balance < 10000.0<_> -> Silver
            | _ -> Gold

    // method to pay the interest
    member this.PayInterest() =
        let interest =
            match this.State with
                | Overdrawn -> 0.
                | Silver -> 0.01
                | Gold -> 0.02
        interest * balance

    // deposit into the account
    member this.Deposit x =
        let a = x
        balance <- balance + a

    // withdraw from account
    member this.Withdraw x =
        balance <- balance - x

// implement the state pattern
let state() =
    let account = Account()

    // deposit 10000 USD
    account.Deposit 10000.<USD>

    // pay interest according to current balance
    printfn "account state = %A, interest = %A" account.State (account.PayInterest())

    // deposit another 2000 USD
    account.Withdraw 2000.<USD>

    // pay interest according to current balance
    printfn "account state = %A, interest = %A" account.State (account.PayInterest())

Execution result from the state pattern sample obtained by invoking the state function

account state = Gold, interest = 200.0
account state = Silver, interest = 80.0

In F#, one way to implement a state machine is with a MailboxProcessor. The F# MailboxProcessor can be viewed as a message queue. It takes an asynchronous workflow as the processing logic. The asynchronous workflow will be introduced in the next chapter, and it can be thought of as a simple function being executed on a background thread. The Post method is used to insert a message into the queue, and the Receive method is used to get the message out of the queue. In Listing 3-20, the variable inbox represents the message queue. When the state machine starts, it goes to state0, which is represented by the state0() function, and waits for user input. The state machine will transition to another state according to the user’s input.

Listing 3-20 State pattern with F# MailBoxProcessor

open Microsoft.FSharp.Control

type States =
    | State1
    | State2
    | State3

type StateMachine() =
    let stateMachine = new MailboxProcessor<States>(fun inbox ->
                let rec state1 () = async {
                    printfn "current state is State1"
                    // <your operations>

                    //get another message and perform state transition
                    let! msg = inbox.Receive()
                    match msg with
                        | State1 -> return! (state1())
                        | State2 -> return! (state2())
                        | State3 -> return! (state3())
                    }
                and state2() = async {
                    printfn "current state is state2"
                    // <your operations>

                    //get another message and perform state transition
                    let! msg = inbox.Receive()
                    match msg with
                        | State1 -> return! (state1())
                        | State2 -> return! (state2())
                        | State3 -> return! (state3())
                    }
                and state3() = async {
                    printfn "current state is state3"
                    // <your operations>

                    //get another message and perform state transition
                    let! msg = inbox.Receive()
                    match msg with
                        | State1 -> return! (state1())
                        | State2 -> return! (state2())
                        | State3 -> return! (state3())
                    }
                and state0 () =
                    async {

                        //get initial message and perform state transition
                        let! msg = inbox.Receive()
                        match msg with
                            | State1 -> return! (state1())
                            | State2 -> return! (state2())
                            | State3 -> return! (state3())
                    }
                state0 ())

    //start the state machine and set it to state0
    do
        stateMachine.Start()

    member this.ChangeState(state) = stateMachine.Post(state)

let stateMachine = StateMachine()
stateMachine.ChangeState(States.State2)
stateMachine.ChangeState(States.State1)

Execution result in FSI

current state is state2
current state is State1

Working with the Factory Pattern

The factory pattern in Listing 3-21 is an object-oriented design pattern used to implement the concept of factories. It uses the function keyword as shortcut to the match statement. It can create an object without specifying the exact class of object that will be created. Listing 3-22 shows an example that uses the object expression to implement the factory pattern.

Listing 3-21 Using the function keyword

// define two types
type Type =
  | TypeA
  | TypeB

// check with function keyword
let checkWithFunction = function
    | TypeA -> printfn "type A"
    | TypeB -> printfn "type B"

// check with match keyword
let checkWithMatch x =
    match x with
    | TypeA -> printfn "type A"
    | TypeB -> printfn "type B"

In Listing 3-22, the factory inside factoryPattern is actually a function. It is a shortcut for a match statement. The checkWithFunction and checkWithMatch functions in Listing 3-21 are equivalent.

Listing 3-22 Example of the factory pattern

// define the interface
type IA =
  abstract Action : unit -> unit

// define two types
type Type =
  | TypeA
  | TypeB

let factoryPattern() =
    // factory pattern to create the object according to the input object type
    let factory = function
      | TypeA -> { new IA with
                       member this.Action() = printfn "I am type A" }
      | TypeB -> { new IA with
                       member this.Action() = printfn "I am type B" }

    // create type A object
    let obj1 = factory TypeA
    obj1.Action()

    // create type B object
    let obj2 = factory TypeB
    obj2.Action()

Execution result from the factory pattern sample obtained by invoking the factoryPattern function

I am type A
I am type B

The factory function returns an object that is not familiar. Actually, the return type is something called an object expression, and this lightweight syntax can simplify your code significantly. If the object is not involved in inheritance, you can pretty much use an object expression to replace a class definition completely. Listing 3-23 shows how to create an instance of interface IA using object expression syntax.

Listing 3-23 Using object expression

// define the interface
type IA =
  abstract Action : unit -> unit

let a = { new IA with
            member this.Action() =
                printfn "this is from object expression" }

Working with the Singleton Pattern

The singleton pattern is a design pattern used to implement the mathematical concept of a singleton. It restricts the instantiation of a class to a single instance. This is useful when exactly one object is needed to coordinate actions across the system. One example of a singleton in F# is a value. An F# value is immutable by default, and this guarantees there is only one instance. Listing 3-24 shows how to make sure that an F# class instance is a singleton. The sample declares a private constructor and ensures that the class has only one instance in memory.

Listing 3-24 An example of the singleton pattern

// define a singleton pattern class
type A private () =
    static let instance = A()
    static member Instance = instance
    member this.Action() = printfn "action from type A"

// singleton pattern
let singletonPattern() =
    let a = A.Instance
    a.Action()

Working with the Composite Pattern

The composite pattern is a partitioning design pattern. The composite pattern describes a group of objects that are to be treated in the same way as a single instance of that object. The typical application is a tree structure representation. Listing 3-25 demonstrates a tree structure. The sample focuses more on how to access this tree structure and bring back the result.

The dynamically generated wrapper object can be treated like a visitor to the tree. The visitor accesses the node and brings the result back to the invoker. In the sample code, the CompositeNode structure not only defines the tree but also defines three common ways to traverse the tree. It does the heavy lifting by encapsulating the tree traversal algorithm. The visitor defines how to process the single node and is responsible for bringing the result back to the invoker. In this sample, the visitor adds the value in the tree nodes and brings back the sum.

Listing 3-25 An example of the composite pattern

// define visitor interface
type IVisitor<'T> =
    abstract member Do : 'T -> unit

// define a composite node
type CompositeNode<'T> =
    | Node of 'T
    | Tree of 'T * CompositeNode<'T> * CompositeNode<'T>
    with
        // define in-order traverse
        member this.InOrder f =
            match this with
            | Tree(n, left, right) ->
                left.InOrder f
                f n
                right.InOrder(f)
            | Node(n) -> f n

        // define pre-order traverse
        member this.PreOrder f =
            match this with
            | Tree(n, left, right) ->
                f n
                left.PreOrder f
                right.PreOrder f
            | Node(n) -> f n

        // define post order traverse
        member this.PostOrder f =
            match this with
            | Tree(n, left, right) ->
                left.PostOrder f
                right.PostOrder f
                f n
            | Node(n) -> f n

let invoke() =
    // define a tree structure
    let tree = Tree(1, Tree(11, Node(12), Node(13)), Node(2))

    // define a visitor, it gets the summary of the node values
    let wrapper =
        let result = ref 0
        ({ new IVisitor<int> with
                member this.Do n =
                    result := !result + n
        }, result)

    // pre-order iterates the tree and prints out the result
    tree.PreOrder (fst wrapper).Do
    printfn "result = %d" !(snd wrapper)

Execution result from the composite pattern sample obtained by calling the invoke function

result = 39

Working with the Template Pattern

The template pattern is, as its name suggests, a program or algorithm skeleton. It is a behavior-based pattern. In F#, we have higher-order functions that can serve as a template to generate other functions. It is natural to use higher-order functions to implement this pattern. Listing 3-26 defines a three-stage database operation function named TemplateF. The actual implementation is provided outside of this skeleton function. I do not assume the database connection and query are all the same, so three functions are left outside of the class definition, and the user can define and pass in their own version of each.

Listing 3-26 An example of the template pattern

// the template pattern takes three functions and forms a skeleton function named TemplateF
type Template(connF, queryF, disconnF) =
    member this.Execute(conStr, queryStr) =
        this.TemplateF conStr queryStr
    member this.TemplateF =
            let f conStr queryStr =
                connF conStr
                queryF queryStr
                disconnF ()
            f

// connect to the database
let connect conStr =
    printfn "connect to database: %s" conStr

// query the database with the SQL query string
let query queryStr =
    printfn "query database %s" queryStr

// disconnect from the database
let disconnect ()  =
    printfn "disconnect"

let template() =
    let s = Template(connect, query, disconnect)
    s.Execute("<connection string>", "select * from tableA")

template()

Execution result from the template pattern sample obtained by invoking the template function

connect to database: <connection string>
query database select * from tableA
disconnect

The class definition is convenient for C# projects that need to reference the implementation of this design pattern in an F# project. However, the class is not necessary in an F#-only solution. Listing 3-27 shows how to use higher-order functions to implement the template pattern.

Listing 3-27 Template pattern with a higher-order function

// connection, query, and disconnect functions
let connect(conStr ) = printfn "connect using %s" conStr
let query(queryStr) = printfn "query with %s" queryStr
let disconnect() = printfn "disconnect"

// template pattern
let template(connect, query, disconnect) (conStr:string) (queryStr:string)=
    connect(conStr)
    query(queryStr)
    disconnect()

// concrete query
let queryFunction = template(connect, query, disconnect)

// execute the query
do queryFunction "<connection string>" "select * from tableA"

Working with the Private Data Class Pattern

The private data class pattern is a design pattern that encapsulates class properties and associated data manipulation. The purpose of the private accessibility is to prevent the modification of these values. C# uses the readonly property, which does not have a setter function, to solve this problem. F# values are immutable by default, so implementing this readonly type of behavior is supported inherently. In the following example, I use an F# record type to implement the pattern by extending the record type. The with keyword in the code shown in Listing 3-28 is a way to tell the compiler that some property, method, or both will be added to the record type. In the sample code, the circle data remains the same once it is created. Some object-oriented implementations even implement another class so that there is little chance to modify the values. The immutability of record types eliminates the needs of a second class, as well as the need for explicitly defining getter-only properties with a keyword.

Listing 3-28 An example of the private data class pattern

type Circle = {
    Radius : float;
    X : float;
    Y : float }



with
    member this.Area = this.Radius**2. * System.Math.PI
    member this.Diameter = this.Radius * 2.
let myCircle = {Radius = 10.0; X = 5.0; Y = 4.5}
printfn "Area: %f Diameter: %f" myCircle.Area myCircle.Diameter

Working with the Builder Pattern

The builder pattern provides abstract steps of building objects. This allows you to pass different implementations of specific abstract steps. Listing 3-29 demonstrates the abstract steps of making a pizza. The invoker can pass in different implementation steps to the cook function to generate different pizzas.

Listing 3-29 An example of the builder pattern sample

// pizza interface
type IPizza =
    abstract Name : string with get
    abstract MakeDough : unit->unit
    abstract MakeSauce : unit->unit
    abstract MakeTopping: unit->unit

// pizza module that defines all recipes
[<AutoOpen>]
module PizzaModule =
    let makeNormalDough() = printfn "make normal dough"
    let makePanBakedDough() = printfn "make pan baked dough"
    let makeCrossDough() = printfn "make cross dough"

    let makeHotSauce() = printfn "make hot sauce"
    let makeMildSauce() = printfn "make mild sauce"
    let makeLightSauce() = printfn "make light sauce"

    let makePepperoniTopping() = printfn "make pepperoni topping"
    let makeFiveCheeseTopping() = printfn "make five cheese topping"
    let makeBaconHamTopping() = printfn "make bacon ham topping"

// define a pepperoni pizza recipe
let pepperoniPizza =
        {   new IPizza with
                member this.Name = "Pepperoni Pizza"
                member this.MakeDough() = makeNormalDough()
                member this.MakeSauce() = makeHotSauce()
                member this.MakeTopping() = makePepperoniTopping() }

// cook takes pizza recipe and makes the pizza
let cook(pizza:IPizza) =
    printfn "making pizza %s" pizza.Name
    pizza.MakeDough()
    pizza.MakeSauce()
    pizza.MakeTopping()

// cook pepperoni pizza
cook pepperoniPizza

Execution result from the builder pattern sample

making pizza Pepperoni Pizza
make normal dough
make hot sauce
make pepperoni topping

The pizza interface and object expression give the program a good structure, but it makes things unnecessarily complicated. The builder pattern requires the actual processing function or functions be passed in, which is a perfect use of higher-order functions. Listing 3-30 uses a higher-order function to eliminate the interface and object expression.

Listing 3-30 Builder pattern implementation using a higher-order function

// pizza module that defines all recipes
[<AutoOpen>]
module PizzaModule =
    let makeNormalDough () = printfn "make normal dough"
    let makePanBakedDough () = printfn "make pan baked dough"
    let makeCrossDough() = printfn "make cross dough"

    let makeHotSauce() = printfn "make hot sauce"
    let makeMildSauce() = printfn "make mild sauce"
    let makeLightSauce() = printfn "make light sauce"

    let makePepperoniTopping() = printfn "make pepperoni topping"
    let makeFiveCheeseTopping() = printfn "make five cheese topping"
    let makeBaconHamTopping() = printfn "make bacon ham topping"

// cook takes the recipe and ingredients and makes the pizza

let cook pizza recipeSteps =
    printfn "making pizza %s" pizza
    recipeSteps
    |> List.iter(fun f -> f())

[ makeNormalDough; makeMildSauce
  makePepperoniTopping ]
|> cook "pepperoni pizza"

Working with the Façade Pattern

The façade pattern provides a higher-level interface that makes invoking an underlying class library easier, more readable, or both. Listing 3-31 shows how to perform an employment background check.

Listing 3-31 An example of the façade pattern

// define Applicant record
type Applicant = { Name : string }

// library to perform various checks
[<AutoOpen>]
module SubOperationModule =
    let checkCriminalRecord (applicant) =
        printfn "checking %s criminal record..." applicant.Name
        true

    let checkPastEmployment (applicant) =
        printfn "checking %s past employment..." applicant.Name
        true

    let securityClearance (applicant, securityLevel) =
        printfn "security clearance for %s ..." applicant.Name
        true

// façade function to perform the background check
let isBackgroundCheckPassed(applicant, securityLevel) =
    checkCriminalRecord applicant
    && checkPastEmployment applicant
    && securityClearance(applicant, securityLevel)

// create an applicant
let jenny = { Name = "Jenny" }

// print out background check result
if isBackgroundCheckPassed(jenny, 2) then printfn "%s passed background check" jenny.Name
else printfn "%s failed background check" jenny.Name

Execution result from the façade pattern sample

checking Jenny criminal record...
checking Jenny past employment...
security clearance for Jenny ...
Jenny passed background check

Working with the Memento Pattern

The memento pattern saves an object’s internal state so that it can be used later. In Listing 3-32, the particle class saves its location information and later restores that information back to the saved location. If the state data is relatively small, a list storage can easily turn the memento pattern into a redo-undo framework.

Listing 3-32 An example of the memento pattern

// define location record
type Location = { X : float; Y : float }

// define a particle class with a location property
type Particle() =
    let mutable loc = {X = 0.; Y = 0.}
    member this.Loc
        with get() = loc
        and private set v = loc <- v
    member this.GetMemento() = this.Loc
    member this.Restore v = this.Loc <- v
    member this.MoveXY(newX, newY) = loc <- { X = newX; Y = newY }


// create a particle
let particle = Particle()

// save current state
let currentState = particle.GetMemento()
printfn "current location is %A" particle.Loc

// move particle to new location
particle.MoveXY(2., 3.)
printfn "current location is %A" particle.Loc

// restore particle to previous saved location
particle.Restore currentState
printfn "current location is %A" particle.Loc