(ship: &S) {
212 | ship.turn_on();
213 | ship.blast_off();
214 | ship.fly();
215 | ship.turn_off();
216 | print("\n");
217 | }
218 |
219 | fn main() {
220 | // Create a new NASAShip
221 | let saturn5 = NASAShip;
222 |
223 | // Let's fly our NASAShip
224 | println("Piloting the Saturn 5.");
225 | pilot(&saturn5);
226 |
227 | // Create a Dragon
228 | let dragon = SpaceXDragon;
229 |
230 | // Uh oh, our pilot function doesn't recognize this ship...
231 | // pilot(&dragon); <-- Gives a compile time error.
232 |
233 | // Let's Adapt our SpaceXDragon ship
234 | let dragon_adapter = SpaceXAdapter {
235 | ship: dragon
236 | };
237 |
238 | // Now we can pilot the Dragon!
239 | println("Piloting the Dragon Adapter.");
240 | pilot(&dragon_adapter);
241 | }
242 |
243 | {% endhighlight %}
244 |
245 | [github]: https://github.com/jdavis/rust-design-patterns/blob/master/patterns/adapter.rs
246 |
--------------------------------------------------------------------------------
/docs/_posts/2013-06-11-chain-of-responsibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Chain of Responsibility
4 | category: behavioral
5 | description: The Chain of Responsibility design pattern in the Rust programming language with an example.
6 | css:
7 | - /css/code.css
8 | - /lib/lightbox/css/lightbox.css
9 | js:
10 | - //ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
11 | - /lib/lightbox/js/lightbox.js
12 | ---
13 |
14 | {{ page.title }}
15 | ================
16 |
17 | ## Definition
18 |
19 | Avoid coupling the sender of a request to its receiver by giving more than one
20 | object a chance to handle the request. Chain the receiving objects and pass the
21 | request along the chain until an object handles it.
22 |
23 | ## Diagram
24 |
25 |
32 |
33 | ## Problem
34 |
35 | TODO
36 |
37 | ## Wrong Solution
38 |
39 | TODO
40 |
41 | ## Correct Solution
42 |
43 | TODO
44 |
45 | ## Example
46 |
47 | TODO
48 |
49 | ### Example Diagram
50 |
51 | TODO
52 |
53 | ### Example Code
54 |
55 | View [chain_of_responsibility.rs][github] on GitHub
56 |
57 | {% highlight rust %}
58 |
59 | // TODO
60 |
61 | {% endhighlight %}
62 |
63 | [github]: https://github.com/jdavis/rust-design-patterns/blob/master/patterns/chain_of_responsibility.rs
64 |
--------------------------------------------------------------------------------
/docs/img/abstract-factory-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdavis/rust-design-patterns/a9fc0673c35f28fdb56142d7dca46cac5fc18dbf/docs/img/abstract-factory-example.png
--------------------------------------------------------------------------------
/docs/img/abstract-factory-structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdavis/rust-design-patterns/a9fc0673c35f28fdb56142d7dca46cac5fc18dbf/docs/img/abstract-factory-structure.png
--------------------------------------------------------------------------------
/docs/img/adapter-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdavis/rust-design-patterns/a9fc0673c35f28fdb56142d7dca46cac5fc18dbf/docs/img/adapter-example.png
--------------------------------------------------------------------------------
/docs/img/adapter-structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdavis/rust-design-patterns/a9fc0673c35f28fdb56142d7dca46cac5fc18dbf/docs/img/adapter-structure.png
--------------------------------------------------------------------------------
/docs/img/chain-of-responsibility-structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdavis/rust-design-patterns/a9fc0673c35f28fdb56142d7dca46cac5fc18dbf/docs/img/chain-of-responsibility-structure.png
--------------------------------------------------------------------------------
/docs/img/rust-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdavis/rust-design-patterns/a9fc0673c35f28fdb56142d7dca46cac5fc18dbf/docs/img/rust-logo.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | id: home
3 | layout: default
4 | title: Home
5 | description: Object oriented design patterns in the Rust programming language.
6 | ---
7 |
8 | Rust Design Patterns
9 |
10 | In Rust we Trust
11 |
12 | About Rust
13 |
14 |
15 | Rust, the programming language, is an
16 | exciting new language that aims to be safe, concurrent, and practical.
17 |
18 |
19 |
20 | It combines the familiar C style syntax that uses curly braces with the
21 | features you'd expect in a modern language.
22 |
23 |
24 |
25 | Rust hopes to "preserve large-system integrity, availability and
26 | concurrency" by the separation it creates between its abstractions and
27 | implementations.
28 |
29 |
30 |
31 | Design Patterns
32 |
33 |
34 | Design patterns have made a resurgence in recent years with the publication
35 | of the 1994 seminal work called Design
36 | Patterns: Elements of Reusable Object-Oriented Software (also called
37 | the Gang of Four book). It provided a catalog of design patterns that could be
38 | used across software systems.
39 |
40 |
41 |
42 | This website takes all the design patterns in the Gang of Four book and
43 | turns them into working examples using the language Rust.
44 |
45 |
46 |
47 | Classes of Design Patterns
48 |
49 | Three classes.
50 |
51 | Creational
52 |
53 |
54 | {% for post in site.categories.creational %}
55 | - {{ post.title }}
56 | {% endfor %}
57 |
58 |
59 | Structural
60 |
61 |
62 | {% for post in site.categories.structural %}
63 | - {{ post.title }}
64 | {% endfor %}
65 |
66 |
67 | Behavioral
68 |
69 |
70 | {% for post in site.categories.behavioral %}
71 | - {{ post.title }}
72 | {% endfor %}
73 |
74 |
75 | Sources
76 |
77 |
78 | As was mentioned, Design Patterns:
79 | Elements of Reusable Object-Oriented Software is the main source of
80 | information provided on this website.
81 |
82 |
83 |
84 | Yet the Gang of Four book isn't the most approachable for newcomers. A
85 | more gentle introduction is the Head
86 | First Design Patterns book. It provides very memorable examples with
87 | easier to understand explanations.
88 |
89 |
90 | Contributing
91 |
92 |
93 | Rust Design Patterns is completely available as open source. It is hosted in
94 | GitHub and can
95 | be forked by anyone.
96 |
97 |
98 |
99 | If you have suggestions on how to make these design patterns better, fork
100 | it and make a pull
102 | request with your updates. If the updates are awesome
103 | (which they probably will be) then the pull requests will be merged into
104 | the main project.
105 |
106 | About
107 |
108 |
109 | Rust Design Patterns is a project that Josh Davis started to learn more
111 | about design patterns. He wanted to learn how to become a better software
112 | engineer yet also learn a new programming language.
113 |
114 |
115 |
116 | If you don't already do so, be sure to follow him on Twitter, GitHub, and Google+.
119 |
--------------------------------------------------------------------------------
/patterns/__init__.py:
--------------------------------------------------------------------------------
1 | # Design Patterns Module
2 |
--------------------------------------------------------------------------------
/patterns/abstract_factory.rs:
--------------------------------------------------------------------------------
1 | /*
2 | * Abstract Factory Design Pattern
3 | * http://joshldavis.com/rust-design-patterns/abstract-factory/
4 | */
5 |
6 | /*
7 | * Core Trait that defines a Phone
8 | */
9 | trait Phone {
10 | fn call(&self);
11 | }
12 |
13 | /*
14 | * Core Trait that defines a Tablet
15 | */
16 | trait Tablet {
17 | fn play_games(&self);
18 | }
19 |
20 | /*
21 | * Core Trait that defines a Factory
22 | */
23 | trait Factory {
24 | fn new_phone(&self) -> P;
25 | fn new_tablet(&self) -> T;
26 | }
27 |
28 |
29 | /*
30 | * Define our Apple products. Normally these structs would contain a lot more
31 | * data.
32 | */
33 | struct IPhone;
34 |
35 | impl Phone for IPhone {
36 | fn call(&self) {
37 | println!("Look! I'm calling on an IPhone!");
38 | }
39 | }
40 |
41 | struct IPad;
42 |
43 | impl Tablet for IPad {
44 | fn play_games(&self) {
45 | println!("Just playing some games on my IPad.");
46 | }
47 | }
48 |
49 | /*
50 | * Create AppleFactory and implement it for our Apple devices
51 | */
52 | struct AppleFactory;
53 |
54 | impl Factory for AppleFactory {
55 | fn new_phone(&self) -> IPhone {
56 | return IPhone;
57 | }
58 |
59 | fn new_tablet(&self) -> IPad {
60 | return IPad;
61 | }
62 | }
63 |
64 | /*
65 | * Define our Google products. Like with Apple's products, these are
66 | * simplified.
67 | */
68 |
69 | struct Nexus4;
70 |
71 | impl Phone for Nexus4 {
72 | fn call(&self) {
73 | println!("Look! I'm calling on a Nexus 4!");
74 | }
75 | }
76 |
77 | struct Nexus10;
78 |
79 | impl Tablet for Nexus10 {
80 | fn play_games(&self) {
81 | println!("Just playing some games on my Nexus 10.");
82 | }
83 | }
84 |
85 | /*
86 | * Create GoogleFactory and implement it for our Google devices
87 | */
88 | struct GoogleFactory;
89 |
90 | impl Factory for GoogleFactory {
91 | fn new_phone(&self) -> Nexus4 {
92 | return Nexus4;
93 | }
94 |
95 | fn new_tablet(&self) -> Nexus10 {
96 | return Nexus10;
97 | }
98 | }
99 |
100 |
101 | fn main() {
102 | // Create our two different factories
103 | let apple = AppleFactory;
104 | let google = GoogleFactory;
105 |
106 | // Both factories use the same interface, so let's just use them
107 |
108 | // Test out creating phones
109 | let phone = apple.new_phone();
110 | phone.call();
111 |
112 | let phone = google.new_phone();
113 | phone.call();
114 |
115 | // Test out creating tablets
116 | let tablet = apple.new_tablet();
117 | tablet.play_games();
118 |
119 | let tablet = google.new_tablet();
120 | tablet.play_games();
121 | }
122 |
--------------------------------------------------------------------------------
/patterns/adapter.rs:
--------------------------------------------------------------------------------
1 | /*
2 | * Adapter Design Pattern
3 | * http://joshldavis.com/rust-design-patterns/adapter/
4 | */
5 |
6 | /*
7 | * Core Trait that defines a basic Rocket Ship
8 | */
9 | trait RocketShip {
10 | fn turn_on(&self);
11 | fn turn_off(&self);
12 | fn blast_off(&self);
13 | fn fly(&self);
14 | }
15 |
16 | /*
17 | * Basic struct for a NASA Ship
18 | */
19 | struct NASAShip;
20 |
21 | /*
22 | * Implement RocketShip trait to add functionality to NASAShip
23 | */
24 | impl RocketShip for NASAShip {
25 | fn turn_on(&self) {
26 | println!("NASA Ship is turning on.")
27 | }
28 |
29 | fn turn_off(&self) {
30 | println!("NASA Ship is turning off.")
31 | }
32 |
33 | fn blast_off(&self) {
34 | println!("NASA Ship is blasting off.")
35 | }
36 |
37 | fn fly(&self) {
38 | println!("NASA Ship is flying away.")
39 | }
40 | }
41 |
42 | /*
43 | * Uh oh, here is our problem. It's the amazingly advanced SpaceX ship that our
44 | * astronaut doesn't know how to pilot.
45 | */
46 | trait SpaceXShip {
47 | fn ignition(&self);
48 | fn on(&self);
49 | fn off(&self);
50 | fn launch(&self);
51 | fn fly(&self);
52 | }
53 |
54 | /*
55 | * Basic struct for a SpaceX Dragon rocket ship
56 | */
57 | struct SpaceXDragon;
58 |
59 | /*
60 | * Implement the SpaceX trait to add functionality to the Space X Dragon
61 | */
62 | impl SpaceXShip for SpaceXDragon {
63 | fn ignition(&self) {
64 | println!("Turning Dragon's ignition.")
65 | }
66 |
67 | fn on(&self) {
68 | println!("Turning on the Dragon.")
69 | }
70 |
71 | fn off(&self) {
72 | println!("Turning off the Dragon.")
73 | }
74 |
75 | fn launch(&self) {
76 | println!("Launching the Dragon")
77 | }
78 |
79 | fn fly(&self) {
80 | println!("The Dragon is flying away.")
81 | }
82 | }
83 |
84 | /*
85 | * Uh oh, the new SpaceXDragon doesn't implement the RocketShip interface. We
86 | * need to create an adapter that does.
87 | */
88 |
89 | /*
90 | * Adapter to adapt anything that implements SpaceXShip to the RocketShip trait
91 | */
92 | struct SpaceXAdapter {
93 | ship: SpaceXDragon
94 | }
95 |
96 | /*
97 | * SpaceX Adapter that adds RocketShip traits to any SpaceXShip
98 | */
99 | impl RocketShip for SpaceXAdapter {
100 | fn turn_on(&self) {
101 | self.ship.ignition();
102 | self.ship.on();
103 | }
104 |
105 | fn turn_off(&self) {
106 | self.ship.off();
107 | }
108 |
109 | fn blast_off(&self) {
110 | self.ship.launch();
111 | }
112 |
113 | fn fly(&self) {
114 | self.ship.fly();
115 | }
116 | }
117 |
118 | /*
119 | * Basic function to pilot ships that implement the RocketShip trait
120 | */
121 | fn pilot(ship: &S) {
122 | ship.turn_on();
123 | ship.blast_off();
124 | ship.fly();
125 | ship.turn_off();
126 | print!("\n");
127 | }
128 |
129 | fn main() {
130 | // Create a new NASAShip
131 | let saturn5 = NASAShip;
132 |
133 | // Let's fly our NASAShip
134 | println!("Piloting the Saturn 5.");
135 | pilot(&saturn5);
136 |
137 | // Create a Dragon
138 | let dragon = SpaceXDragon;
139 |
140 | // Uh oh, our pilot function doesn't recognize this ship...
141 | // pilot(&dragon); <-- Gives a compile time error.
142 |
143 | // Let's Adapt our SpaceXDragon ship
144 | let dragon_adapter = SpaceXAdapter {
145 | ship: dragon
146 | };
147 |
148 | // Now we can pilot the Dragon!
149 | println!("Piloting the Dragon Adapter.");
150 | pilot(&dragon_adapter);
151 | }
152 |
--------------------------------------------------------------------------------
/patterns/chain_of_responsibility.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | }
3 |
--------------------------------------------------------------------------------
/patterns/decorator.py:
--------------------------------------------------------------------------------
1 | """
2 | Decorator Pattern
3 |
4 | Definition:
5 | pass
6 |
7 | Also Known As:
8 | pass
9 |
10 | Problem:
11 | pass
12 |
13 | Wrong Solution:
14 | pass
15 |
16 | Correct Solution:
17 | pass
18 |
19 | Sources:
20 | Title: Head First Design Patterns
21 | Author(s): Eric Freeman & Elisabeth Freeman
22 | Pages: 79-107
23 |
24 | Title: Design Patterns
25 | Author(s): Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
26 | Pages: 175-184
27 |
28 | Example Info:
29 | pass
30 |
31 | """
32 |
--------------------------------------------------------------------------------
/patterns/factory.py:
--------------------------------------------------------------------------------
1 | """
2 | Factory Pattern
3 |
4 | Definition:
5 | This pattern defines an interface for creating an object, but lets
6 | subclasses decide which class to instantiate. Factory Method lets a class
7 | defer instantiation to subclasses.
8 |
9 | Also Known As:
10 | Virtual Constructor
11 |
12 | Problem:
13 | pass
14 |
15 | Wrong Solution:
16 | pass
17 |
18 | Correct Solution:
19 | pass
20 |
21 | Sources:
22 | Title: Head First Design Patterns
23 | Author(s): Eric Freeman & Elisabeth Freeman
24 | Pages: 109-168
25 |
26 | Title: Design Patterns
27 | Author(s): Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
28 | Pages: 107-116
29 |
30 | Example Info:
31 | pass
32 |
33 | """
34 |
--------------------------------------------------------------------------------
/patterns/observer.py:
--------------------------------------------------------------------------------
1 | """
2 | Observer Pattern
3 |
4 | Definition:
5 | Define a one-to-many dependency between objects so that when one object
6 | changes state, all its dependents are notified and updated automatically.
7 |
8 | Also Known As:
9 | Dependents
10 | Publish-Subscribe (PubSub)
11 |
12 | Problem:
13 | An often encountered problem in programming is when a value in a class,
14 | Class A, must be updated. This is usually easy but what would happen if
15 | there are multiple classes that must be told about this value change?
16 |
17 | Wrong Solution:
18 | There are a few wrong ways to solve this problem. One solution (more common
19 | in threaded applications, such as GUI applications) is to just poll the
20 | given value every x seconds. This is bad because it adds unneeded CPU usage.
21 |
22 | Another solution is to create some sort of update method on Class A as well
23 | as a method on any of the other classes that rely on the value. This update
24 | method would be called whenever the value changes. Once it is called it
25 | would would then call each method on the dependent class to let it know
26 | that the value changed. While this is closer to the solution, it would
27 | require modifying the update method of Class A everytime a new class relies
28 | on another class.
29 |
30 | Correct Solution:
31 | The correct solution is to instead register each dependent class with Class
32 | A upon creation. Class A would then keep track of all the classes that are
33 | now 'registered' with it. Then once a value changes, it would then notify
34 | each class that has been registered. This allows an arbitrary number of
35 | classes to 'observe' a value and moves the registration act outside of the
36 | Class A.
37 |
38 | Sources:
39 | Title: Head First Design Patterns
40 | Author(s): Eric Freeman & Elisabeth Freeman
41 | Pages: 37-78
42 |
43 | Title: Design Patterns
44 | Author(s): Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
45 | Pages: 293-299
46 |
47 | Example Info:
48 | The example showing the Observer pattern uses a system familiar to all, a
49 | library. When a book is checked out, the library then creates a wait list.
50 | Anyone that would like to checkout the book is added to the list. Then once
51 | the book changes status, all* of the patrons on the list are notified.
52 |
53 | *This is slightly different than normal libraries. This list isn't FIFO
54 | like most libraries. This example was modified for pedagogical purposes;
55 | simpler is easier to understand.
56 |
57 | """
58 |
59 | import sys
60 |
61 |
62 | class Patron(object):
63 | """
64 | Class representing a patron of the library. Each patron has a name as well
65 | as a method to contact them.
66 |
67 | """
68 |
69 | def __init__(self, name):
70 | self.name = name
71 |
72 | def phone_call(self, message):
73 | print message
74 |
75 |
76 | class Book(object):
77 | """
78 | Class representing a book that is at the library. The book is responsible
79 | for knowing who has checked it out and who is waiting for it. (Similar to
80 | how each book record in the database would managed.)
81 |
82 | """
83 |
84 | def __init__(self, title):
85 | self.title = title
86 | self.checked_out_by = None
87 | self.wait_list = []
88 |
89 |
90 | class Library(object):
91 | """
92 | Class representing a library. It has methods for checking out a book and
93 | returning one.
94 |
95 | Note:
96 | It is a strange library in a way. Rather than hold the book for the
97 | first person on the waitlist, it just broadcasts a message to everyone
98 | on the waitlist and the first person to check it out gets the book.
99 |
100 | """
101 |
102 | def __init__(self):
103 | pass
104 |
105 | def checkout_book(self, patron, book):
106 | if book.checked_out_by is not None:
107 | print 'Sorry,', patron.name + '.'
108 | print 'The book', book.title, 'is already checked out.'
109 | print 'We will add you to the wait list.'
110 | book.wait_list.append(patron)
111 |
112 | return
113 |
114 | if patron in book.wait_list:
115 | book.wait_list.remove(patron)
116 |
117 | print patron.name, 'you have successfully checked out', book.title
118 | book.checked_out_by = patron
119 |
120 | def return_book(self, book):
121 | book.checked_out_by = None
122 |
123 | message = 'The book ' + book.title + ' has been returned.'
124 |
125 | for patron in book.wait_list:
126 | prefix = 'Hello, ' + patron.name + '. '
127 | patron.phone_call(prefix + message)
128 |
129 |
130 | def main(args):
131 | library = Library()
132 |
133 | bobby = Patron('Bobby Tables')
134 | billy = Patron('Billy')
135 | isaac = Patron('Isaac')
136 |
137 | dune = Book('Dune')
138 |
139 | library.checkout_book(bobby, dune)
140 | library.checkout_book(billy, dune)
141 | library.checkout_book(isaac, dune)
142 |
143 | library.return_book(dune)
144 |
145 |
146 | if __name__ == '__main__':
147 | sys.exit(main(sys.argv))
148 |
--------------------------------------------------------------------------------
/patterns/strategy.py:
--------------------------------------------------------------------------------
1 | """
2 | Strategy Pattern
3 |
4 | Definition:
5 | The Strategy pattern defines a family of algorithms, encapsulates each one,
6 | and makes them interchangeable. Strategy lets the algorithm vary
7 | independently from clients that use it.
8 |
9 | Also Known As:
10 | Policy
11 |
12 | Problem:
13 | Almost all programmers have ran into this issue before. The issue is when a
14 | programmer is tasked with creating a Class A that does a task. This Class A
15 | performs that task like expected and works quite well. However, the problem
16 | arises when the programmer is told that Class A isn't sufficient. Instead,
17 | a Class B must also be created but that task must be performed differently.
18 | Since Class A isn't simple, it contains many other methods and instance
19 | variables. Let's view the solutions below to see what can be done to solve
20 | this problem.
21 |
22 | Wrong Solution:
23 | The wrong solution is to think that this problem should be solved using
24 | inheritance. It is wrong because this solution is not scalable. Whenever
25 | the task needs to be completed differently, Class A needs to be inherited
26 | to override the task. A problem can arise when Class A adds functionality
27 | that shouldn't exist in Class B.
28 |
29 | Correct Solution:
30 | The correct solution is to implement this Strategy pattern. Rather than
31 | inherit Class A and override the task, the programmer will create a
32 | TaskBehavior that is an interface. This interface is simple and just
33 | performs a single task. Now the TaskBehavior interface is implemented two
34 | different ways, for the first task and the second task. Next, Class A is
35 | just given a simple instance variable to contain this new TaskBehavior.
36 | Whenever Class A wishes to perform this task, it instead calls the task on
37 | the given TaskBehavior.
38 |
39 | Sources:
40 | Title: Head First Design Patterns
41 | Author(s): Eric Freeman & Elisabeth Freeman
42 | Pages: 2-24
43 |
44 | Title: Design Patterns
45 | Author(s): Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
46 | Pages: 315-323
47 |
48 | Example Info:
49 | This examle uses my favorite activity/sport to illustrate the Strategy
50 | pattern. It uses Bicycles as its example classes.
51 |
52 | A Bicycle is an object that consists of two algorithms that have been
53 | encapsulated: ShiftBehavior and RideBehavior. Essentially, the idea is that
54 | a Bicycle has the same universal parts across all instances. Road bikes,
55 | mountain bikes fixies, and all others have two wheels, a saddle, a frame,
56 | chain, pedals, and so on. The main difference is how it performs shifting.
57 | So the idea of this example abstracts that out to another class.
58 |
59 | The second thing that it abstracts out is the riders. Bikes can be ridden
60 | by many people so after a Bicycle is created, the method `set_rider` will
61 | allow you to change who is on it.
62 |
63 | This example may seem strange for a few reasons. It is using some
64 | psuedo-interfaces, since Python doesn't have support for real interfaces.
65 | Instead, a base class is created that just raises an exception if that
66 | class were to be instantiated and a method performed on it. This is strange
67 | in that interfaces might seem slightly un-pythonic in some eyes.
68 |
69 | Despite this, the example should (hopefully) make sense. Enjoy!
70 |
71 | """
72 |
73 | import sys
74 |
75 |
76 | class Bicycle(object):
77 | """
78 | Main class that encapsulates both of our behaviors: ShiftBehavior and
79 | RideBehavior.
80 |
81 | Allows dynamic changing of riders because bikes can be swapped.
82 |
83 | Methods that begin with perform_ are proxy methods for a behavior.
84 |
85 | """
86 |
87 | def __init__(self, shifter):
88 | self.shifter = shifter
89 | self.rider = None
90 |
91 | def set_rider(self, behavior):
92 | self.rider = behavior
93 | behavior.speed = 0
94 |
95 | def perform_pedal(self):
96 | if self.rider is None:
97 | print 'No one is on the bike! Call set_rider first.'
98 | return
99 |
100 | self.rider.pedal()
101 |
102 | def perform_shift_up(self):
103 | if self.rider is None:
104 | print 'No one is on the bike! Call set_rider first.'
105 | return
106 |
107 | self.shifter.shift_up()
108 |
109 | def perform_shift_down(self):
110 | if self.rider is None:
111 | print 'No one is on the bike! Call set_rider first.'
112 | return
113 |
114 | self.shifter.shift_down()
115 |
116 | #
117 | # Behavior "Interfaces"
118 | #
119 |
120 |
121 | class ShiftBehavior(object):
122 | """
123 | Our base ShiftBehavior. All new shifting behaviors should inherit from this
124 | class.
125 |
126 | """
127 |
128 | def __init__(self):
129 | pass
130 |
131 | def shift_up(self):
132 | raise NotImplementedError('Shift_up method is not implemented')
133 |
134 | def shift_down(self):
135 | raise NotImplementedError('Shift_down method is not implemented')
136 |
137 |
138 | class RideBehavior(object):
139 | """
140 | Our base RideBehavior. All new rider behaviors should inherit from this
141 | class.
142 |
143 | """
144 |
145 | def __init__(self):
146 | pass
147 |
148 | def pedal(self):
149 | raise NotImplementedError('Pedal method is not implemented')
150 |
151 | #
152 | # Different Shift Behaviors
153 | #
154 |
155 |
156 | class RoadBikeShifter(ShiftBehavior):
157 | """
158 | Inherit our base ShiftBehavior and implement some basic road bike
159 | mechanics.
160 |
161 | """
162 |
163 | def __init__(self):
164 | super(RoadBikeShifter, self).__init__()
165 | self.gears = 20
166 | self.current_gear = 1
167 |
168 | def shift_up(self):
169 | if self.current_gear >= self.gears:
170 | print 'Can\'t shift up anymore! Already at gear', self.gears
171 | return
172 |
173 | self.current_gear += 1
174 |
175 | print 'Shifted up to:', self.current_gear
176 |
177 | def shift_down(self):
178 | if self.current_gear <= 1:
179 | print 'Can\'t shift down anymore! Already at the lowest gear'
180 | return
181 |
182 | self.current_gear -= 1
183 |
184 | print 'Shifted down to:', self.current_gear
185 |
186 |
187 | class SingleSpeedShifter(ShiftBehavior):
188 | """
189 | Inherit our base ShiftBehavior and implement some basic single speed bike
190 | mechanics.
191 |
192 | """
193 |
194 | def __init__(self):
195 | super(SingleSpeedShifter, self).__init__()
196 | self.gears = 1
197 |
198 | def shift_up(self):
199 | print 'This is a single speed bike!'
200 |
201 | def shift_down(self):
202 | print 'This is a single speed bike!'
203 |
204 | #
205 | # Different Ride Behaviors
206 | #
207 |
208 |
209 | class OldGeezer(RideBehavior):
210 | """
211 | Inherit our base RideBehavior and implement the pedal method at the speed
212 | of an old geezer on a Sunday cruise after church.
213 |
214 | """
215 |
216 | def __init__(self):
217 | super(OldGeezer, self).__init__()
218 | self.speed = 0
219 | self.rate = 1
220 |
221 | def pedal(self):
222 | self.speed += self.rate
223 |
224 | print 'Speed is now', self.speed
225 |
226 |
227 | class BradleyWiggins(RideBehavior):
228 | """
229 | Inherit our base RideBehavior and implement the pedal method except at the
230 | speed of Bradley Wiggins.
231 |
232 | """
233 |
234 | def __init__(self):
235 | super(BradleyWiggins, self).__init__()
236 | self.speed = 0
237 | self.rate = 10
238 |
239 | def pedal(self):
240 | self.speed += self.rate
241 |
242 | print 'Wow, Bradley Wiggins is a beast!'
243 | print 'Speed is now', self.speed
244 |
245 |
246 | def main(args):
247 | # Create our RideBehaviors
248 | geezer = OldGeezer()
249 | wiggo = BradleyWiggins()
250 |
251 | # Create the ShiftBehaviors
252 | single_speed_shifter = SingleSpeedShifter()
253 | road_bike_shifter = RoadBikeShifter()
254 |
255 | # Create our bikes with the shifting
256 | road_bike = Bicycle(road_bike_shifter)
257 | single_speed = Bicycle(single_speed_shifter)
258 |
259 | # Mount our bikes
260 | road_bike.set_rider(wiggo)
261 | single_speed.set_rider(geezer)
262 |
263 | # Test out our shifting
264 | print '\nTesting out road bike with Wiggo...'
265 | road_bike.perform_shift_up()
266 | road_bike.perform_pedal()
267 |
268 | print '\nTesting out single speed bike with geezer...'
269 | single_speed.perform_shift_up()
270 | single_speed.perform_pedal()
271 |
272 | print '\nSwapping riders...'
273 | single_speed.set_rider(wiggo)
274 | road_bike.set_rider(geezer)
275 |
276 | print '\nTesting road bike with geezer...'
277 | road_bike.perform_shift_up()
278 | road_bike.perform_pedal()
279 |
280 |
281 | if __name__ == '__main__':
282 | sys.exit(main(sys.argv))
283 |
--------------------------------------------------------------------------------
/scripts/build_docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Set our variables
4 | MAIN_BRANCH="master"
5 | DOC_BRANCH="gh-pages"
6 | DOCS_DIR="docs"
7 | SITE_DIR="_site"
8 |
9 | #
10 | # Documentation functions
11 | #
12 |
13 | # Prints the basic usage of build_docs.sh.
14 | function usage() {
15 | echo usage: build_docs.sh [commands...]
16 | echo
17 | echo Commands:
18 | echo "\tbuild\t\tBuilds Jekyll documentation"
19 | echo "\tdeploy\t\tCommits and pushes changes"
20 | echo "\tserve\t\tUses Jekyll's built-in server"
21 | }
22 |
23 | # Uses Jekyll to serve up the documentation.
24 | function serve() {
25 | echo Serving up documentation...
26 | echo
27 |
28 | jekyll serve --watch --source $DOCS_DIR --destination $SITE_DIR
29 | }
30 |
31 | # Checkouts the gh-pages branch, commits the generated documentation and then
32 | # pushes it.
33 | function deploy() {
34 | echo Deploying documentation...
35 | echo
36 |
37 | git checkout $DOC_BRANCH || {
38 | echo "Failed to checkout $DOC_BRANCH"
39 | exit 1
40 | }
41 |
42 | cp -a $SITE_DIR/* ./
43 |
44 | git add .
45 | git commit -m "AUTO: Update generated documentation"
46 | git push origin $DOC_BRANCH
47 |
48 | git checkout $MAIN_BRANCH
49 |
50 | echo
51 | echo Deploy finished.
52 | }
53 |
54 | # The default function, it just builds the documentation using Jekyll.
55 | function build() {
56 | echo Building documentation...
57 | echo
58 |
59 | # Build documentation
60 | jekyll build --source $DOCS_DIR --destination $SITE_DIR
61 | }
62 |
63 | # Do a few sanity checks...
64 |
65 | hash git >> /dev/null 2>&1 || {
66 | echo "Oh dear. I require Git, but it's not installed."
67 | exit 1
68 | }
69 |
70 | hash jekyll >> /dev/null 2>&1 || {
71 | echo "Oh dear. It looks like jekyll isn't installed."
72 | exit 1
73 | }
74 |
75 | # Move to the root directory...
76 |
77 | GIT_DIR=`git rev-parse --show-toplevel`
78 |
79 | if [[ $PWD != $GIT_DIR ]]; then
80 | echo "Changing to the Git root directory..."
81 | cd $GIT_DIR
82 | fi
83 |
84 | if [[ $# -eq 0 ]]; then
85 | usage
86 | else
87 | # Run functions for the arguments given
88 | for cmd in "$@"
89 | do
90 | case "$cmd" in
91 | "build")
92 | build;;
93 | "deploy")
94 | deploy;;
95 | "serve")
96 | serve;;
97 | *)
98 | usage;;
99 | esac
100 | done
101 | fi
102 |
--------------------------------------------------------------------------------