-
Notifications
You must be signed in to change notification settings - Fork 5
/
gui_factory.rb
121 lines (112 loc) · 4.24 KB
/
gui_factory.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
module Creational
module AbstractFactory
# This example demonstrates the AbstractFactory pattern
# using classes for a simple cross platform GUI application.
#
# [Problem] There is a an application which needs to run on both Win
# and OSX platforms. Depending on the platform, the application
# needs to use the correct type of GUI components, like buttons.
# If the application knows about all the types of components,
# it's going to turn messy when a new platform or a new type
# of component is to be added.
# [Solution] Use AbstractFactory pattern to abstract object creation
# based on the family the object belongs to (Win/OSX).
# ConcreteFactories - WinFactory and OsxFactory implement
# methods to return products of their families.
# WinButton and OsxButtons are the products that belong
# to Win and OSX families respectively
# [Collaborators]
# AbstractFactory:: {GuiFactory}
# AbstractProduct:: {AbstractButton}
# ConcreteFactories:: {WinFactory}, {OsxFactory}
# ConcreteButtons:: {WinButton}, {OsxButton}
# Client:: {Application}
module GuiFactoryExample
# [Role] AbstractFactory
# This is the AbstractFactory class.
# You don't really need this in Ruby thanks to duck typing.
# But we'll make sure every subclass implements the instance methods.
# Notice the NotImplementedError?
# That makes sure every subclass of GuiFactory overrides its methods,
# else it raises a NotImplemented error
class GuiFactory
def create_button
raise NotImplementedError, "#{self.class.name} does not implement create_button()"
end
end
# [Role] AbstractProduct
# This is the AbstractProduct class.
# You don't really need this in Ruby thanks to duck typing.
# But we'll make sure every subclass implements the instance methods.
# Notice the NotImplementedError?
# That makes sure every subclass of AbstractButton overrides its methods,
# else it raises a NotImplemented error
class AbstractButton
def paint
raise NotImplementedError, "#{self.class.name} does not implement paint()"
end
end
# [Role] ConcreteFactory
# This is a ConcreteFactory class
# It implements the operations to create
# a ConcreteProduct object, in this case,
# a WinButton object.
# It should override all methods declared
# in AbstractFactory
class WinFactory < GuiFactory
def create_button
return WinButton.new
end
end
# [Role] ConcreteFactory
# This is a ConcreteFactory class
# It implements the operations to create
# a ConcreteProduct object, in this case,
# an OsxButton object.
# It should override all methods declared
# in AbstractFactory
class OsxFactory < GuiFactory
def create_button
return OsxButton.new
end
end
# [Role] ConcreteProduct
# This is a ConcreteProduct class
# How to create a WinButton is abstracted
# into this class.
# It should override all methods declared
# in AbstractProduct
class WinButton < AbstractButton
def paint
puts "I'm a WinButton"
end
end
# [Role] ConcreteProduct
# This is a ConcreteProduct class
# How to create an OsxButton is abstracted
# into this class.
# It should override all methods declared
# in AbstractProduct
class OsxButton < AbstractButton
def paint
puts "I'm an OsxButton"
end
end
# [Role] Client
# This is the Client.
# It uses only those interfaces provided by
# the AbstractFactory which is GuiFactory
# and the AbstractProduct which is the AbstractButton
# classes.
class Application
def initialize(gui_factory)
@gui_factory = gui_factory
end
def run
button = @gui_factory.create_button
button.paint
end
end
end #GuiFactoryExample
end #AbstractFactory
end #Creational