72
1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

Embed Size (px)

Citation preview

Page 1: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

1

Software Architecture

Bertrand Meyer

ETH Zurich, March-July 2009

Lecture 10: More patterns: Factory, Builder, Singleton

Page 2: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

2

Some design patterns

Creational Abstract Factory Builder Factory Method Prototype Singleton

Structural Adapter Bridge Composite Decorator Façade Flyweight Proxy

Behavioral Chain of

Responsibility Command

(undo/redo) Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor

Page 3: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

3

Some design patterns

Creational Abstract Factory Builder Factory Method Prototype Singleton

Structural Adapter Bridge Composite Decorator Façade Flyweight Proxy

Behavioral Chain of

Responsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor

Page 4: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

4

Creational patterns

Hide the creation process of objectsHide the concrete type of these objectsAllow dynamic and static configuration of the system

Page 5: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

5

Explicit creation in O-O languages

Eiffel:

create x.make (a, b, c)

C++, Java, C#:x = new T (a, b, c)

Page 6: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

6

Abstract factory

“Provide[s] an interface for creating families of related or dependent objects without specifying their concrete classes.” [Gamma et al.]

Page 7: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

7

Abstract Factory: example

Widget toolkit (EiffelVision, Java Swing) Different look and feel, e.g. for Unix & Windows Family of widgets: Scroll bars, buttons, dialogs… Want to allow changing look & feel

Most parts of the system need not know what look & feel is used

Creation of widget objects should not be distributed

Page 8: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

8

Abstract Factory usage

Abstract Factory is not just the syntactic replacement of

create {T } x.make (1)by

x := factory.new_t (2)

because: T could be a deferred class

then (1) would not be possible

factory can take advantage of polymorphism

Page 9: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

9

Abstract factory architecture

*FACTORY

+FACTORY_1

+FACTORY_2

*PRODUCT_A

+PRODUCT_A1

+PRODUCT_A2

+PRODUCT_B1

+PRODUCT_B2

*PRODUCT_B

new_product_a*

new_product_b*

new_product_a+

new_product_b+new_product_b+

new_product_a+

Page 10: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

10

Abstract widget factory example

UNIX_

FACTORY +

FACTORY *

WIN_

FACTORY +

UNIX_

BUTTON +

BUTTON *

WIN_

BUTTON +

UNIX_

CHECKBOX +

CHECKBOX *

WIN_

CHECKBOX +

new_button *

new_button+

new_button+

new_box+

new_box+

new_box *

Page 11: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

11

Class FACTORY

deferred classFACTORY

feature -- Basic operations

new_button : BUTTON is-- New button

deferredend

new_checkbox : CHECKBOX is -- New checkbox

deferredend

…end

Page 12: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

12

An example concrete factory: WIN_FACTORY

classWIN_FACTORY

inheritFACTORY

feature -- Basic operationsnew_button : BUTTON

-- New Windows buttondo

create {WIN_BUTTON } Resultend

new_checkbox : CHECKBOX-- New Windows checkbox

docreate {WIN_CHECKBOX } Result

end…

end

Page 13: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

13

Shared ancestor for factory clients

classSHARED_FACTORY

…feature -- Basic operations

factory : FACTORY-- Factory used for widget instantiation

onceif is_windows_os then

create {WIN_FACTORY } Resultelse

create {UNX_FACTORY } Result

endend

…end

Page 14: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

14

Usage of FACTORY

class WIDGET_APPLICATION

inheritSHARED_FACTORY

…feature -- Basic operations

some_feature-- Generate a new button and use it.

localmy_button : BUTTON

do…my_button := factory.new_button…

end…end

Abstract notion

Does not name platform

Page 15: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

15

Reasons for using an abstract factory

Most parts of a system should be independent of how its objects are created, are represented and collaborate

The system needs to be configured with one of multiple families

A family of objects is to be designed and only used together

You want to support a whole palette of products, but only show the public interface

Page 16: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

16

Abstract factory pattern: properties

Isolates concrete classes Makes exchanging product families easy Promotes consistency among products Supporting new kinds of products is difficult

Page 17: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

17

Abstract factory pattern: criticism

Code redundancy: The factory classes, e.g. UNIX_FACTORY and

WIN_FACTORY will be similar

Lack of flexibility: FACTORY fixes the set of factory functions

new_button and new_box

Page 18: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

18

Our factory example

UNIX_

FACTORY +

FACTORY *

WIN_

FACTORY +

UNIX_

BUTTON +

BUTTON *

WIN_

BUTTON +

UNIX_

CHECKBOX +

CHECKBOX *

WIN_

CHECKBOX +

new_button *

new_button+

new_button+

new_box+

new_box+

new_box *

Page 19: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

19

Beyond patterns

A pattern is an architectural solutionEach programmer who needs the pattern has to learn it (externals and internals) and reimplement it for every application)Similar to traditional learning of algorithms and data structures

Can we do better: use components instead?

It’s better to reuse than do redo.

(if reuse occurs through an API)

Page 20: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

20

Components over patterns

Easier to learn

No need to learn implementation

Professional implementation will be better than manually crafted one

But: do we lose generality?

Page 21: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

21

The key to pattern componentization

Genericity Constrained genericity Multiple inheritance Agents Contracts (to make sure we get everything right)

Page 22: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

22

The Factory library

classFACTORY [G ]create

makefeature -- Initialization

make (f : like factory_function)-- Initialize with factory_function set to f.

requireexists: f /= Void

dofactory_function := f

endfeature -- Access

factory_function : FUNCTION [ANY, TUPLE [], G ]-- Factory function creating new instances of type

G

Page 23: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

23

The Factory library

feature -- Factory operationsnew : G

-- New instance of type Gdofactory_function.call ([])Result := factory_function.last_result

ensureexists: Result /= Void

end

new_with_args (args : TUPLE ): G-- New instance of type G initialized with args

dofactory_function.call (args)Result := factory_function.last_result

ensureexists: Result /= Void

endinvariant

exists: factory_function /= Voidend

Page 24: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

24

Sample application

In class SIMULATION : simulated_traffic : TRAFFIC

simulated_traffic.add_vehicle (…)

VEHICLE*

CAR+

BUS+

METRO+

TRAFFIC+

SIMULATION+

Page 25: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

25

With the Abstract Factory pattern

With:

car_factory : CAR_FACTORY -- Factory of cars

once create Result

ensure exists: Result /=

Void end

VEHICLE_FACTORY*

CAR_FACTORY+

BUS_FACTORY+

METRO_FACTORY+new_car+ new_metro+

new_vehicle*

new_bus+

simulated_traffic.add_vehicle ( car_factory.new_car (p, d, w, h))

Page 26: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

26

With the Factory library

simulated_traffic.add_vehicle (car_factory.new_with_args ([p, d, w, h]))

With:

car_factory : FACTORY [CAR]-- Factory of cars

oncecreate Result.make (agent new_car)

ensureexists: Result /= Void

end

Page 27: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

27

With the Factory library

and:

new_car (p, d, w, h : INTEGER ):CAR-- New car with power engine p,-- wheel diameter d, -- door width w, door height h

do-- Create car engine, wheels, and doors.create Result.make (engine, wheels, doors)

ensureexists: Result /= Void

end

Page 28: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

28

Factory library: create several products

An instance of FACTORY describes one kind of product:class

FACTORY [G]…feature -- Factory functions

new: G … -- New instance of type G

new_with_args (args: TUPLE ): G … -- New instance of type G initialized with args

end

Use several factory objects to create several products:class

LIBRARY…feature -- Factories

fb : FACTORY [CAR ]fu : FACTORY [TRUCK ]

end

Page 29: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

29

Factory pattern vs. library

Benefits: Get rid of some code duplication Fewer classes Reusability

Limitation: Likely to yield a bigger client class (because

similarities cannot be factorized through inheritance)

Page 30: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

30

Factory Method pattern

Intent:“Define[s] an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.” [Gamma et al.]

C++, Java, C#: emulates constructors with names

Factory Method vs. Abstract Factory: Creates one object, not families of object. Works at the routine level, not class level. Helps a class perform an operation, which

requires creating an object. Features new and new_with_args of the Factory

Library are factory methods

Page 31: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

31

Explicit creation in O-O languages

Eiffel:

create x.make (a, b, c)

C++, Java, C#:x = new T (a, b, c)

Page 32: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

32

Managing parallel hierarchies with factories

classWINDOW

…feature button: BUTTON menu_bar: MENU_BAR…end

*WIDGET

*BUTTON

*CONTAINER

*WINDOW

*MENU_BAR

+WEL_

WINDOW

+GTK_

WINDOW

+WEL_

MENU_BAR

+GTK_

MENU_BAR

+WEL_

BUTTON

+GTK_

BUTTON

We want to use factories to create WINDOWs

Page 33: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

33

With an Abstract Factory (1/6)

deferred class

WINDOW_FACTORY

feature -- Factory functions

new_window: WINDOW is deferred endnew_button: BUTTON is deferred endnew_menu_bar: MENU_BAR is deferred end

…end

Page 34: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

34

With an Abstract Factory (2/6)

Factory ensures that all widgets of the window are Windows widgets

classWEL_WINDOW_FACTORY

inheritWINDOW_FACTORY

createmake

feature {NONE } -- Initializationmake (…) is …

feature -- Factory functionsnew_window: WEL_WINDOW is …new_button: WEL_BUTTON is …new_menu_bar: WEL_MENU_BAR is …

…end

Page 35: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

35

With an Abstract Factory (3/6)

Factory ensures that all widgets of the window are Unix widgets

classGTK_WINDOW_FACTORY

inheritWINDOW_FACTORY

createmake

feature {NONE } -- Initializationmake (…) is …

feature -- Factory functionsnew_window : GTK_WINDOW is …new_button : GTK_BUTTON is …new_menu_bar : GTK_MENU_BAR is …

…end

Page 36: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

36

With an Abstract Factory (4/6)

deferred classAPPLICATION

…feature -- Initialization

build_window is-- Build window.

localwindow: WINDOW

dowindow := window_factory.new_window…

endfeature {NONE } -- Implementation

window_factory: WINDOW_FACTORY-- Factory of windows

invariantwindow_factory_not_void: window_factory /= Void

end

Page 37: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

37

With an Abtract Factory (5/6)

classWEL_APPLICATION

inheritAPPLICATION

createmake

feature {NONE } -- Initialization make is

-- Create window_factory. do create {WEL_WINDOW_FACTORY }

window_factory.make(…)

end…end

Page 38: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

38

With an Abtract Factory (6/6)

classGTK_APPLICATION

inheritAPPLICATION

createmake

feature {NONE} -- Initialization make is

-- Create window_factory. do create {GTK_WINDOW_FACTORY }

window_factory.make(…)

end…end

Page 39: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

39

With the Factory Library (1/3)The Factory Library can create only one kind of product

classFACTORY [G]

…feature -- Factory functions

new: G is … -- New instance of type G

new_with_args (args : TUPLE ): G is … -- New instance of type G initialized with args

end

Use several factory objects to create several productsclass

LIBRARY…feature -- Factories

fb: FACTORY [BOOK ]fu: FACTORY [USER ]

end

Page 40: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

40

With the Factory Library (2/3)

deferred classAPPLICATION

…feature -- Initialization

build_window is-- Build window.

localwindow: WINDOW

dowindow := window_factory.new…

endfeature {NONE } -- Implementation

window_factory: FACTORY [WINDOW ]button_factory: FACTORY [BUTTON ]menu_bar_factory: FACTORY [MENU_BAR ]

…end

Page 41: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

41

With the Factory Library (3/3)

• Client must make sure that all factories are configured to create Windows widgets

• More error-prone with several factories

However, the problem already existed in the Abstract Factory pattern; it is concentrated in class WINDOW_FACTORY

classWEL_APPLICATION

inheritAPPLICATION

createmake

featuremake is

-- Create factories. do

create {FACTORY [WEL_WINDOW ]} window_factory.make (…)

create {FACTORY [WEL_BUTTON ]} button_factory.make (…)

create {FACTORY [WEL_MENU_BAR ]} menu_bar_factory.make (…)

end…end

Page 42: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

42

With an Abstract Factory

Factory ensures that all widgets of the window are Windows widgets

classWEL_WINDOW_FACTORY

inheritWINDOW_FACTORY

createmake

feature {NONE } -- Initializationmake (…) is …

feature -- Factory functionsnew_window: WEL_WINDOW is …new_button: WEL_BUTTON is …new_menu_bar: WEL_MENU_BAR is …

…end

Page 43: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

43

Prototype pattern

Intent: “Specify the kinds of objects to create using a

prototypical instance, and create new objects by copying this prototype.” [Gamma 1995]

CLIENT PROTOTYPEtwinprototype

Class

Client

No need for this in Eiffel: just use function twin from class ANY.

y := x.twin

In Eiffel, every object is a prototype

Page 44: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

44

Cloning in Java, C#, and Eiffel

Java Class must implement the interface Cloneable

defining clone (to have the right to call clone defined in Object)

C# Class must implement the interface ICloneable

defining Clone (to have the right to call MemberwiseClone defined in Object)

Next version of Eiffel Class must broaden the export status of clone,

deep_clone inherited from ANY (not exported in ANY)

Page 45: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

45

Builder pattern

Purpose “Separate the construction of a complex object

from its representation so that the same construction process can create different representations”

(Gamma et al.)

Example use: build a document out of components (table of contents, chapters, index…) which may have some variants.

Page 46: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

46

Builder pattern

CLIENT*

BUILDER

+MY_BUILDER MY_PRODUCT

PART_A

my_builder

last_product+

PART_B

part_a

part_b

build build*

last_product*

build+

build_product

build_part_a

build_part_b

set_part_a

set_part_b

Page 47: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

47

Builder Library

deferred classBUILDER [G]

feature -- Accesslast_product : G

-- Product under constructiondeferredend

feature -- Status reportis_ready : BOOLEAN

-- Ready to build last_product ?deferredend

feature -- Basic operationsbuild

-- Build last_product.require

is_ready: is_readydeferredensure

last_product_exists: last_product /= Voidend

end

Mechanisms enabling componentization: unconstrained genericity, agents

+ Factory Library

Page 48: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

48

Two-part builder

classTWO_PART_BUILDER [F −> BUILDABLE, G, H]

-- F: type of product to build-- G: type of first part of the product-- H: type of second part of the product

The builder knows the type of product to build and number of parts

In the original Builder pattern: Deferred builder does not know the type of product

to build Concrete builders know the type of product to build

TWO_PART_BUILDER is a concrete builder compatible with the pattern

Page 49: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

49

Example using a two-part builder

classAPPLICATION

createmake

feature {NONE } -- Initializationmake is

-- Build a new two-part product with a two-part builder.local my_builder: TWO_PART_BUILDER [TWO_PART_PRODUCT,

PART_A, PART_B ] my_product: TWO_PART_PRODUCTdo create my_builder.make (agent new_product, agent new_part_a,

agent new_part_b) my_builder.build_with_args (["Two-part product"],["Part A"],["Part

B"]) my_product := my_builder.last_productend

feature -- Factory functionsnew_product (a_name: STRING ): TWO_PART_PRODUCT is …new_part_a (a_name: STRING ): PART_A is …new_part_b (a_name: STRING ): PART_B is …

end

Page 50: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

50

Two-part builder (1/4)

class interfaceTWO_PART_BUILDER [F −> BUILDABLE, G, H ]

inheritBUILDER [F ]

createmake

feature {NONE } -- Initializationmake (f: like factory_function_f; g : like factory_function_g;

h: like factory_function_h) -- Set factory_function_f to f. Set factory_function_g to g. -- Set factory_function_h to h.require

f_not_void: f /= Voidg_not_void: g /= Voidh_not_void: h /= Void

ensurefactory_function_f_set: factory_function_f = ffactory_function_g_set: factory_function_g = gfactory_function_h_set: factory_function_h = h

feature -- Accesslast_product : F

-- Product under construction

Page 51: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

51

Two-part builder (2/4)

feature -- Status reportis_ready: BOOLEAN

-- Is builder ready to build last_product?valid_args (args_f, args_g, args_h: TUPLE ): BOOLEAN

-- Are args_f, args_g and args_h valid arguments to

-- build last_product?

feature -- Basic operationsbuild

-- Build last_product. (Successively call build_g and

-- build_h to build product parts.)do

last_product := f_factory.newbuild_g ([])build_h ([])

ensure theng_not_void: last_product.g /= Voidh_not_void: last_product.h /= Void

end

Page 52: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

52

Two-part builder (3/4)

build_with_args (args_f, args_g, args_h: TUPLE )-- Build last_product with args_f. (Successively-- call build_g with args_g and build_h with-- args_h to build product parts.)

requirevalid_args: valid_args (args_f, args_g, args_h )

ensureg_not_void: last_product.g /= Voidh_not_void: last_product.h /= Void

feature -- Factory functionsfactory_function_f: FUNCTION [ANY, TUPLE, F ]

-- Factory function creating new instances of type F

factory_function_g: FUNCTION [ANY, TUPLE, G ]-- Factory function creating new instances of

type Gfactory_function_h: FUNCTION [ANY, TUPLE, H ]

-- Factory function creating new instances of type H

Page 53: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

53

Two-part builder (4/4)

feature {NONE } -- Basic operationsbuild_g (args_g: TUPLE ) is …build_h (args_h: TUPLE ) is …

feature {NONE } -- Factoriesf_factory: FACTORY [F ]

-- Factory of objects of type Fg_factory: FACTORY [G ]

-- Factory of objects of type Gh_factory: FACTORY [H ]

-- Factory of objects of type Hinvariant

factory_function_f_not_void: factory_function_f /= Voidfactory_function_g_not_void: factory_function_g /= Voidfactory_function_h_not_void: factory_function_h /= Voidf_factory_not_void: f_factory /= Voidg_factory_not_void: g_factory /= Voidh_factory_not_void: h_factory /= Void

end

Page 54: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

54

Builder Library using factories?Very flexible because one can pass any agent as long as it has a matching signature and creates the product parts

classTWO_PART_BUILDER [F −> BUILDABLE, G, H ]

inheritBUILDER [F ]

…feature -- Factory functions

factory_function_f: FUNCTION [ANY, TUPLE, F ]-- Factory function creating new instances of type F

factory_function_g: FUNCTION [ANY, TUPLE, G ]-- Factory function creating new instances of type G

factory_function_h: FUNCTION [ANY, TUPLE, H ]-- Factory function creating new instances of type H

feature {NONE } -- Implementationbuild_g (args_g : TUPLE ) is

-- Set last_product.g with a new instance of type G created with -- arguments args_g.do

last_product.set_g (g_factory.new_with_args (args_g ))…

end…end

Page 55: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

55

Builder Library: completeness?

Supports builders that need to create two-part or three-part products

Cannot know the number of parts of product to be built in general

Incomplete support of the Builder pattern (“Componentizable but non-comprehensive”)

Page 56: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

56

Singleton pattern

Way to “ensure a class only has one instance, and to provide a global point of access to it.” [Gamma et al.]

Page 57: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

57

Singleton pattern

Way to “ensure a class only has one instance, and to provide a global point of access to it.” [GoF, p 127]

SINGLETONSHARED_

SINGLETON

singleton

Global point of access

Page 58: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

58

Basic Eiffel singleton mechanism

Once routines

But: does not prevent cloning

Page 59: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

59

Once routines

If instead of

r isdo

... Instructions ...end

you write

r isonce

... Instructions ...end

then Instructions will be executed only for the first call by any client during execution. Subsequent calls return immediately.

In the case of a function, subsequent calls return the result computed by the first call.

Page 60: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

60

Scheme for shared objects

class MARKET_INFO feature Christmas : DATE once create Result.make (...) end off_days : LIST [DATE] once create Result.make (...) Result.extend (Christmas) ... end ...end

class APPLICATION_CLASS inherit MARKET_INFO

featurer is

do print

(off_days) ...end

...end

Page 61: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

61

Singleton and cloning in Eiffel

Class ANY has features clone (twin), deep_clone, … One can duplicate any Eiffel object, which rules

out the Singleton pattern clone, deep_clone, … will be exported to NONE

in the next version of Eiffel possible to have singletons

Page 62: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

62

Cloning in Java, C#, and Eiffel

Java Class must implement the interface Cloneable

defining clone (to have the right to call clone defined in Object)

C# Class must implement the interface ICloneable

defining Clone (to have the right to call MemberwiseClone defined in Object)

Next version of Eiffel Class must broaden the export status of clone,

deep_clone inherited from ANY (not exported in ANY)

Page 63: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

63

Basic singleton implementation*

classSINGLETON

feature {NONE} -- Implementationfrozen the_singleton: SINGLETON

-- Unique instance of this classonce

Result := Currentend

invariantonly_one_instance: Current = the_singleton

end

*Jézéquel, Train, Mingins, Design Patterns and Contracts, Addison-Wesley 1999

Page 64: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

64

Singleton pattern use

deferred classSHARED_SINGLETON

feature {NONE} -- Implementationsingleton: SINGLETON is

-- Access to a unique instance. (Should be redefined -- as once function in concrete descendants.)deferredend

is_real_singleton : BOOLEAN is -- Do multiple calls to singleton return the same

result?do

Result := singleton = singletonend

invariantsingleton_is_real_singleton: is_real_singleton

end

Page 65: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

65

Singleton pattern issue

Problem: Allows only one singleton per system

the_singleton: once function inherited by all descendants of SINGLETON

Þ would keep the same valueÞ would violate the invariant of SINGLETON in all

its descendants, except the one for which the singleton was created first

Page 66: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

66

Singleton and system correctness

The Singleton property“There exists only one object of this class”

is a global invariant of the system.

However, Eiffel assertions are only at a class-level, not at the system-level.

For a guaranteed singleton property in current Eiffel: see Karine Arnout’s thesis

Page 67: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

67

Frozen classes

Class that may not have any descendantMarked by a keyword frozenA class cannot be both frozen and deferred

Advantages: Straightforward way to implement singletons No problem of different once statuses Compilers can optimize code of frozen classes

Weakness: Goes against the Open-Closed principle

Page 68: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

68

Singleton with frozen classes

frozen classSHARED_SINGLETON

feature -- Accesssingleton: SINGLETON is

-- Global access point to singletononce

create Resultensure

singleton_not_void: Result /= Voidend

end

classSINGLETON

create {SHARED_SINGLETON}

default_create

end

Page 69: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

69

Singleton without frozen classes

Frozen classes require the ability to restrict the exportation of creation procedures (constructors)

Not applicable in Java and C++

Java and C++ use static features to implement the Singleton pattern:

A class Singleton with a protected constructor and a static function Instance() that creates the singleton if it was not yet created, otherwise returns it (use of a private field _instance).

Page 70: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

70

Complementary material (1/3)

From Patterns to Components: Chapter 18: Singleton

Further reading: Erich Gamma: Design Patterns, 1995.

(Singleton, p 127-134)

Karine Arnout and Éric Bezault. “How to get a Singleton in Eiffel”, JOT, 2004. http://www.jot.fm/issues/issue_2004_04/article5.pdf.

Paul Cohen. “Re: Working singleton implementation”. comp.lang.eiffel. http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF-8&selm=3AD984B6.CCEC91AA%40enea.se&rnum=8.

Page 71: 1 Software Architecture Bertrand Meyer ETH Zurich, March-July 2009 Lecture 10: More patterns: Factory, Builder, Singleton

71

Complementary material (2/3)

Further reading: Joshua Fox. “When is a singleton not a singleton?”,

JavaWorld, 2001. http://www.javaworld.com/javaworld/jw-01-2001/jw-0112-singleton.html.

David Geary. “Simply Singleton”, JavaWorld, 2003. http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html.

Robert C. Martin. “Singleton and Monostate”, 2002. http://www.objectmentor.com/resources/articles/SingletonAndMonostate.pdf.