├── .gitignore ├── LICENSE-MIT ├── Makefile ├── PRINCIPLES.md ├── README.md ├── TODO.md ├── docs ├── .gitignore ├── 404.html ├── README.md ├── _config.yml ├── _layouts │ └── default.html ├── _plugins │ └── inlineh.rb ├── _posts │ ├── 2013-01-01-using-a-design-pattern.md │ ├── 2013-01-01-what-is-a-design-pattern.md │ ├── 2013-06-11-abstract-factory.md │ ├── 2013-06-11-adapter.md │ └── 2013-06-11-chain-of-responsibility.md ├── img │ ├── abstract-factory-example.png │ ├── abstract-factory-structure.png │ ├── adapter-example.png │ ├── adapter-structure.png │ ├── chain-of-responsibility-structure.png │ └── rust-logo.png └── index.html ├── patterns ├── __init__.py ├── abstract_factory.rs ├── adapter.rs ├── chain_of_responsibility.rs ├── decorator.py ├── factory.py ├── observer.py └── strategy.py └── scripts └── build_docs.sh /.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | *~ 3 | *.sw[po] 4 | *.py[co] 5 | _site/ 6 | build/ 7 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012 Josh Davis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RUSTC=printf "\033[32;1mRustc:\033[33m %s\033[m\n" $@; rustc 2 | SRC=$(wildcard patterns/*.rs) 3 | PROG:=$(patsubst patterns/%.rs,build/%,$(SRC)) 4 | RUSTFLAGS= 5 | 6 | .SILENT: 7 | .PRECIOUS: $(LIBSTAMP) 8 | 9 | all: exe 10 | # Build executables 11 | 12 | help: 13 | # Show this help 14 | grep -A1 ^[a-z].*\: Makefile | sed -r 's/: (.*)$$/:/g' | sed ':a;N;$$!ba;s/:\n//g' | sed s,\\#,\\t,g | grep -v \\-- 15 | 16 | clean: 17 | # Remove executables 18 | rm -fr $(PROG) build/ patterns/*~ *~ 19 | 20 | exe: $(PROG) 21 | # Build executables 22 | 23 | run: $(PROG) 24 | # Run executables 25 | @for EXE in $(PROG); do\ 26 | printf "\033[33;1m%s\033[m\n" $$EXE;\ 27 | ./$$EXE;\ 28 | done 29 | 30 | version: 31 | # Display version of source code 32 | git describe 33 | 34 | %: build/% 35 | printf "\033[33;1m%s\033[m\n" $< 36 | $< 37 | 38 | build/% : patterns/%.rs 39 | mkdir -p build 40 | $(RUSTC) $(RUSTFLAGS) $< -o $@ 41 | -------------------------------------------------------------------------------- /PRINCIPLES.md: -------------------------------------------------------------------------------- 1 | Design Principles 2 | ================= 3 | 4 | from Head First Design Patterns. 5 | 6 | 1. Identify the aspects of your application that vary and separate them from 7 | what stays the same. 8 | 9 | 2. Program to an interface, not an implementation. 10 | 11 | 3. Favor composition over inheritance. 12 | 13 | 4. Classes should be open for extension, but closed for modification. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Design Patterns in Rust 2 | ========================= 3 | 4 | > **Note:** This used to be a repository for design patterns in Python, it is in 5 | > the process of being converted over into Rust. 6 | 7 | Implementation of various design patterns in a new and exciting language called 8 | [Rust][rust]. 9 | 10 | These are supposed to be simple examples to not only illustrate the design 11 | pattern, but to make it easier to remember. 12 | 13 | Using 14 | ----- 15 | 16 | To learn about a given pattern, open up the source code. All of the patterns are 17 | defined in the [patterns][patterns] directory. 18 | 19 | To run a given pattern, just run it like this: 20 | 21 | ```bash 22 | 23 | # Be in the repository 24 | $ cd design-patterns/ 25 | 26 | # Run the Adapter pattern 27 | $ make adapter 28 | 29 | ``` 30 | 31 | Be sure to take a look at the [list of patterns][list]. 32 | 33 | Also included is the complete list of [Design Principles][principles] listed in 34 | the book, [Head First Design Patterns][hfdp], from order of introduction. It is 35 | a great resource that reminds one on some very important principles when it 36 | comes to software design. 37 | 38 | 39 | Learning 40 | -------- 41 | 42 | All of the patterns can be found in the [patterns][patterns] directory. 43 | 44 | To learn about a given pattern, just navigate to the [documentation][docs] page for the 45 | design patterns. 46 | 47 | Each design pattern will have: 48 | 49 | 1. A definition 50 | 2. List of alternative names (if the pattern has any) 51 | 3. A common problem the pattern solves 52 | 4. A wrong solution 53 | 5. A correct solution using the pattern 54 | 6. Sources used for the pattern for continued reading 55 | 56 | List of Patterns 57 | ---------------- 58 | 59 | * [Adapter](http://joshldavis.com/rust-design-patterns/adapter/) 60 | * [Abstract Factory](http://joshldavis.com/rust-design-patterns/abstract-factory/) 61 | 62 | Sources 63 | ------- 64 | 1. **Title**: Head First Design Patterns 65 | 66 | **Author(s)**: Eric Freeman & Elisabeth Freeman 67 | 68 | **Link(s)**: [Site][hfdp], [Amazon][hfdpa] 69 | 70 | 71 | 2. **Title**: Design Patterns: Elements of Reusable Object-Oriented Software 72 | 73 | **Author(s)**: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 74 | 75 | **Link(s)**: [Wikipedia][GoFW], [Amazon][GoFA] 76 | 77 | [rust]: http://www.rust-lang.org/ 78 | [documentation]: http://joshldavis.com/rust-design-patterns/ 79 | [GoFA]: http://amzn.com/0201633612 80 | [GoFW]: http://en.wikipedia.org/wiki/Design_Patterns 81 | [list]: #list-of-patterns 82 | [hfdp]: http://www.headfirstlabs.com/books/hfdp/ 83 | [hfdpa]: http://amzn.com/0596007124 84 | [patterns]: patterns/ 85 | [principles]: PRINCIPLES.md 86 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | TODO 2 | ==== 3 | 4 | ## Basics 5 | 6 | - [ ] Fix up adapter.rs pattern 7 | - [x] Create script that autogenerates documentation from code 8 | - [ ] Add code automatically when building (no duplication) 9 | - [ ] Add basic Design Pattern info 10 | - [ ] Add complete list of patterns on side 11 | 12 | ## Types of Design Patterns 13 | 14 | - [ ] Structural 15 | - [ ] Behavioral 16 | - [ ] Creational 17 | 18 | ## Design Patterns 19 | 20 | - [ ] Abstract Factory 21 | - [ ] Builder 22 | - [ ] Factory Method 23 | - [ ] Prototype 24 | - [ ] Singleton 25 | - [ ] Adapter 26 | - [ ] Bridge 27 | - [ ] Composite 28 | - [ ] Decorator 29 | - [ ] Facade 30 | - [ ] Flyweight 31 | - [ ] Proxy 32 | - [ ] Chain of Responsibility 33 | - [ ] Command 34 | - [ ] Interpreter 35 | - [ ] Iterator 36 | - [ ] Mediator 37 | - [ ] Memento 38 | - [ ] Observer 39 | - [ ] Strategy 40 | - [ ] Template Method 41 | - [ ] Visitor 42 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 - Josh Davis 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 | My cat, Rocket 21 | Josh Davis 22 |
23 | 24 |

Josh Davis

25 | 26 |

27 | I'm a Computer Science major that is interning at Amazon in Seattle. 28 |

29 |

30 | I like to learn, pet kittens, and wear fluffy socks. 31 |

32 |

33 | I never save anything for the swim back. 34 |

35 | 36 | 43 | 44 |

45 | 46 | 47 | 48 | 49 | 50 |

51 |
52 | 53 |
54 |
55 |

Uh oh, 404 error.

56 |

This isn't what you were looking for, is it?

57 | Rocket is a sexy cat. 58 |
59 |
60 |
61 | 62 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Rust Desgin Patterns 2 | ==================== 3 | 4 | Files for the `gh-pages` branch for [Rust Design Patterns](http://joshldavis.com/rust-design-patterns). 5 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | safe: false 2 | pygments: true 3 | permalink: /:title 4 | markdown: rdiscount 5 | plugins: docs/_plugins/ 6 | 7 | title: Rust Design Patterns - Josh Davis 8 | name: Rust Design Patterns 9 | description: Design Patterns in Rust Language 10 | base: http://joshldavis.com/ 11 | url: http://joshldavis.com/rust-design-patterns 12 | feed: /atom.xml 13 | 14 | author: Josh Davis 15 | contact: hello@joshldavis.com 16 | 17 | css: 18 | - /css/base.css 19 | - /lib/font-awesome/css/font-awesome.min.css 20 | - http://fonts.googleapis.com/css?family=Droid+Sans 21 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% if page.title %}{{ page.title }} - {% endif %}{{ site.title }} 6 | 7 | 8 | 9 | 10 | {% for css in site.css %} 11 | 12 | {% endfor %} 13 | {% if page.id == 'home' %} 14 | {% for css in site.posts.first.css %} 15 | 16 | {% endfor %} 17 | {% else %} 18 | {% for css in page.css %} 19 | 20 | {% endfor %} 21 | {% endif %} 22 | 23 | 24 | 25 | 26 | Fork me on GitHub 27 | 28 |
29 |
30 | 33 | 34 | 37 | 38 |

Rust Design Patterns

39 | 47 | 48 |

Creational

49 | 54 | 55 |

Structural

56 | 61 | 62 |

Behavioral

63 | 68 |
69 | 70 |
71 |
72 | {{ content }} 73 |
74 |
75 |
76 | 77 | 87 | {% for js in site.js %} 88 | 89 | {% endfor %} 90 | {% if page.id == 'home' %} 91 | {% for js in site.posts.first.js %} 92 | 93 | {% endfor %} 94 | {% else %} 95 | {% for js in page.js %} 96 | 97 | {% endfor %} 98 | {% endif %} 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/_plugins/inlineh.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Jekyll Plugin to embed code from a file 3 | # Source: http://stefan.artspace44.com/2013/highlight-source-files-in-jekyll/ 4 | # 5 | 6 | module Jekyll 7 | class RenderTimeTag < Liquid::Tag 8 | def initialize(tag_name, text, tokens) 9 | super 10 | parts = text.split(" "); 11 | @filename = parts[0]; 12 | @type = parts[1..(-1)].join(" ") || "text"; 13 | path = File.join('html', @filename); 14 | if File.exists?(path) 15 | @content = File.read(path) 16 | else 17 | @content = "" 18 | end 19 | @highlighter = Liquid::Template.tags["highlight"].new( 20 | "highlight", @type, [@content, "{% endhighlight %}"]); 21 | end 22 | 23 | def render(context) 24 | link = "#{@filename}:" 25 | code = @highlighter.render(context) 26 | "#{link}\n\n#{code}" 27 | end 28 | end 29 | end 30 | 31 | Liquid::Template.register_tag('inlineh', Jekyll::RenderTimeTag) 32 | -------------------------------------------------------------------------------- /docs/_posts/2013-01-01-using-a-design-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: How do you use a Design Pattern? 4 | category: info 5 | description: Explanation of how to appropriately apply a Design Pattern. 6 | --- 7 | 8 | {{ page.title }} 9 | ================ 10 | 11 | First it is very important to understand [what a design pattern is][what]. 12 | 13 | After understanding what it is and why you would want to use a design pattern, 14 | the steps of using a design pattern can be summarized as below: 15 | 16 | 1. Identity a Problem 17 | 2. Find a Design Pattern 18 | 3. Understand the Design Pattern 19 | 4. Look at the Example 20 | 5. Fit the Pattern 21 | 6. Implement the Pattern 22 | 23 | ## Identity a Problem 24 | 25 | It is very easy to design software in an ad-hoc fashion by adding functions and 26 | classes whenever the need arises. The problem with this is that it doesn't work 27 | well for large projects or when multiple develop on the same project. 28 | 29 | The way to remedy this is to think about how you want to do something before you 30 | actually do it. By doing this, you can look at the trade-offs and shortcomings 31 | whenever you make a decision about the structure of your code. 32 | 33 | A few examples of the things developers do when they come across a problem and 34 | don't design a solution for it: 35 | 36 | 1. I need code to do X. I'll add it to this object. Oh, this code also needs to 37 | be in this object? I'll just copy and paste it. 38 | 2. I need to reuse code across different objects. I'll just make a dummy object 39 | that only contains that method. 40 | 41 | By designing instead of coding blindly, the following problems might arise 42 | in comparison: 43 | 44 | 1. If I were to use inheritance here to solve X problem, what side effects would 45 | it have when this code needs to be extended for Y? 46 | 2. If I split up the classes in this way, it will solve X. Will that make it 47 | easier to understand if problem Y arises? 48 | 49 | The second set of questions accurately looks at the side-effects of every action 50 | in a code base. 51 | 52 | Out of the six steps, this might be the most difficult one to master. It 53 | requires the ability to examine decisions and being able to see the trade-offs 54 | when designing software. 55 | 56 | ## Find a Design Pattern 57 | 58 | If the problem has been accurately understood, the next thing to do is to find a 59 | Design Pattern that will either solve the problem or lessen the impact of it. 60 | 61 | This requires knowing some design patterns or at least knowing the categories 62 | that they fall in. When you know that the problem you are solving deals with 63 | object instances and instantiating them effectively, it would help to look at 64 | Creational design patterns. 65 | 66 | For the complete list of design patterns that this website has, view the 67 | [homepage][home]. 68 | 69 | ## Understand the Design Pattern 70 | 71 | Once you've selected the design pattern that will help you. It is well worth 72 | your time to understand it fully. 73 | 74 | Each design pattern on this site has eight parts: 75 | 76 | 1. A definition 77 | 2. List of alternative names (if any) 78 | 3. A diagram showing a [UML][uml] representation of the pattern 79 | 4. A common problem the pattern solves 80 | 5. A wrong solution 81 | 6. A correct solution using the pattern 82 | 7. Consequences of using the pattern 83 | 8. Example code 84 | 85 | After understanding it, if it doesn't actually solve your problem, you may have 86 | to go to the previous step of finding one that might solve it. 87 | 88 | Have a look at the [Adapter Design Pattern][adapter] to see what this looks 89 | like. 90 | 91 | ## Look at the Example 92 | 93 | The example will provide a self contained use case of the pattern in action. It 94 | will show how to structure the classes/interfaces and it will show the 95 | functions/methods that will need to interact together. 96 | 97 | The example can be also used as a template for what you wish to do. The next 98 | step will look what might happen if your problem requires a lot more effort to 99 | solve. You may wish to just use it as a reference and make further 100 | modifications based on your specific use case. 101 | 102 | ## Fit the Pattern 103 | 104 | The problem that you have might not fit the given problem exactly. For whatever 105 | the reason may be, it may be required to make certain changes to either your 106 | structure or to the design pattern. 107 | 108 | It may be the case that you are already using another design pattern as well. 109 | You may have to make them work together and do other things to improve the 110 | design of your software. 111 | 112 | ## Implement the Pattern 113 | 114 | The implementation of a design pattern will vary greatly depending on the 115 | language, package layout, and other factors of the software environment. 116 | 117 | However, the core idea does not change. An example of this would be implementing 118 | the Observer pattern in Rust as compared to Java. 119 | 120 | In Java, you could use polymorphism or an interface when creating your observer 121 | pattern. 122 | 123 | In Rust, this changes a bit. Rust doesn't have inheritance or polymorphism. It 124 | does have traits which is very similar to an interface. A Rust programmer 125 | wouldn't be able to use polymorphism in this case. 126 | 127 | ## Final Thoughts 128 | 129 | By using a design pattern, the quality of your code and software can be greatly 130 | increased. It's important to realize the benefit that they can provide and what 131 | problems they may solve. 132 | 133 | [home]: / 134 | [what]: /rust-design-patterns/what/ 135 | [observer]: /rust-design-patterns/observer/ 136 | [adapter]: /rust-design-patterns/adapter/ 137 | [uml]: http://en.wikipedia.org/wiki/Unified_Modeling_Language 138 | -------------------------------------------------------------------------------- /docs/_posts/2013-01-01-what-is-a-design-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: What is a Design Pattern? 4 | category: info 5 | description: Explanation of what a Design Pattern actually is. 6 | --- 7 | 8 | {{ page.title }} 9 | ================ 10 | 11 | A design pattern is a way to organize and structure software. While the idea 12 | isn't quite intuitive unless you have a basic understanding of building 13 | software, let's look at it from a neutral perspective using an analogy. 14 | 15 | ## Cathedral Analogy 16 | 17 | Imagine you live in the 12th century and are appointed to lead the construction 18 | of a cathedral. Your name may or may not be [Tom Builder][pillars]. 19 | 20 | This might seem like a daunting task if you don't have much experience with 21 | building cathedrals. To give you a foundation (ha, pun) so that you can start 22 | designing it, you want to study other famous cathedrals. 23 | 24 | As you view more and more cathedrals and talk to various other cathedral 25 | builders, you start to notice certain "patterns" among the great structures. For 26 | example, you may notice that certain vaulting requires more robust support. You 27 | might notice that certain materials work better for certain parts of the 28 | cathedral because it is lighter or possibly sturdier than others. 29 | 30 | In order to help future cathedral builders, you want to compile all that you've 31 | learned into a single volume to help other builders. You want the information 32 | to be as general as possible such that it can help the most number of people as 33 | they design and build. 34 | 35 | This is exactly what a design pattern is. The fact that it has to do with 36 | architecture instead of software engineering doesn't matter. The goal of a 37 | design pattern is always to provide a common solution to a certain problem when 38 | designing something. 39 | 40 | ## Software as the Cathedral 41 | 42 | This isn't the first time that software has been likened to building a 43 | cathedral; Eric S. Raymond also used the comparison for open source software in 44 | his seminal essay, [The Cathedral and the Bazaar][esr]. 45 | 46 | The idea is still the same; when designing software there are times when 47 | programming it a certain way will bring far more benefits than the easier 48 | approach or vice versa. 49 | 50 | The hard part is understanding the benefits and shortcomings of various design 51 | patterns and recognizing when to use them. 52 | 53 | ## Why would you use/not use a Design Pattern? 54 | 55 | A design pattern can improve various aspects of software engineering. Whether it 56 | has to do with the immediate improvement of speed to develop, or the future of 57 | the code base in ways you might not expect. 58 | 59 | When a design pattern isn't appropriately selected, it can have negative side 60 | effects on software development. It's important to choose design patterns based 61 | on the problem they are trying to solve. 62 | 63 | Here are a few important measurements that design patterns can greatly change. 64 | 65 | ### Development Speed 66 | 67 | A design pattern can hinder the speed of development if a sophisticated design 68 | isn't needed. 69 | 70 | Conversely, using a known design pattern can speed up development because it 71 | alleviates the hassle of having to think about how all your classes will 72 | interact and work together. 73 | 74 | ### Readability 75 | 76 | Readability in programming is a measurement of how easy it is to look at a piece 77 | (however big) of code and understand what it is doing. 78 | 79 | By taking software and changing it so that it fits well-known problems, it gives 80 | people that aren't familiar with your code base (new developers, managers, 81 | maintainers, etc.) an easier starting point and an easier time when trying to 82 | understand the code. 83 | 84 | Sometimes one of the hardest parts about understanding a code base is just 85 | understanding why things are arranged the way they are. The more you can do to 86 | put things in a logical and well-thought out manner, the less a person reading 87 | the code will have to do to understand it. Design patterns give a tried and tested 88 | format as guidelines for doing this. 89 | 90 | ### Maintainability 91 | 92 | Another measurement that is closely tied to readability, is a way of looking at 93 | how easy it is to add features and fix bugs in an existing project or code base. 94 | 95 | While all programmers are wishful thinkers in that we hope to write code that 96 | will solve the problem once and never be modified, that is rarely the case. 97 | 98 | There are various design patterns (such as the [Strategy][strategy]) 99 | 100 | ### Simplicity 101 | 102 | There is no denying that a simple approach can sometimes be the best for the 103 | given project. By using a design pattern, you risk adding more classes and 104 | obfuscating the code. 105 | 106 | [strategy]: / 107 | [pillars]: http://en.wikipedia.org/wiki/The_Pillars_of_the_Earth 108 | [esr]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ 109 | -------------------------------------------------------------------------------- /docs/_posts/2013-06-11-abstract-factory.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Abstract Factory 4 | category: creational 5 | description: Abstract factory design pattern in the Rust programming language with 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 | Also Known As: **Kit** 18 | 19 | ## Definition 20 | 21 | Provide an interface for creating families of related or dependent objects 22 | without specifying their concrete classes. 23 | 24 | ## Diagram 25 | 26 | 32 | 33 | ## Problem 34 | 35 | There are times when one is programming on a project and there are a group of 36 | objects that have something in common. Sometimes the project will also have a 37 | set of these groups and need to use them interchangeably. 38 | 39 | The problem is when we want to use these groups of objects interchangeably yet 40 | creating the objects becomes a hassle. 41 | 42 | ## Wrong Solution 43 | 44 | One way to handle this is to just make multiple `if` statements in the code for 45 | when objects are created. If the system is in this state, create this object of 46 | group A, if the system is in this state, create this object of group B and so 47 | on. 48 | 49 | ## Correct Solution 50 | 51 | The right way to take care of this is to use the Abstract Factory pattern. 52 | Instead of making giant `if` statements, we want to program to an interface 53 | instead and use the power of object-oriented programming. 54 | 55 | ## Example 56 | 57 | Apple and Google both make tablets and phones. Each company has a different way 58 | of creating their products and obviously have different factories where they 59 | create them. 60 | 61 | The thing is that a website that sells Apple and Google devices doesn't care 62 | about how the factory makes the products. Instead it cares about how to ask the 63 | factory for a phone/tablet when it needs to. All it cares about is that each 64 | factory works the same way. In programmer terminology, each factory has the same 65 | *interface*. 66 | 67 | ### Example Diagram 68 | 69 | 75 | 76 | ### Example Code 77 | 78 | View [abstract_factory.rs][github] on GitHub 79 | 80 | {% highlight rust %} 81 | 82 | /* 83 | * Abstract Factory Design Pattern 84 | * http://joshldavis.com/rust-design-patterns/abstract-factory/ 85 | */ 86 | 87 | /* 88 | * Core Trait that defines a Phone 89 | */ 90 | trait Phone { 91 | fn call(&self); 92 | } 93 | 94 | /* 95 | * Core Trait that defines a Tablet 96 | */ 97 | trait Tablet { 98 | fn play_games(&self); 99 | } 100 | 101 | /* 102 | * Core Trait that defines a Factory 103 | */ 104 | trait Factory { 105 | fn new_phone(&self) -> P; 106 | fn new_tablet(&self) -> T; 107 | } 108 | 109 | 110 | /* 111 | * Define our Apple products. Normally these structs would contain a lot more 112 | * data. 113 | */ 114 | struct iPhone; 115 | 116 | impl Phone for iPhone { 117 | fn call(&self) { 118 | println("Look! I'm calling on an iPhone!"); 119 | } 120 | } 121 | 122 | struct iPad; 123 | 124 | impl Tablet for iPad { 125 | fn play_games(&self) { 126 | println("Just playing some games on my iPad."); 127 | } 128 | } 129 | 130 | /* 131 | * Create AppleFactory and implement it for our Apple devices 132 | */ 133 | struct AppleFactory; 134 | 135 | impl Factory for AppleFactory { 136 | fn new_phone(&self) -> iPhone { 137 | return iPhone; 138 | } 139 | 140 | fn new_tablet(&self) -> iPad { 141 | return iPad; 142 | } 143 | } 144 | 145 | /* 146 | * Define our Google products. Like with Apple's products, these are 147 | * simplified. 148 | */ 149 | 150 | struct Nexus4; 151 | 152 | impl Phone for Nexus4 { 153 | fn call(&self) { 154 | println("Look! I'm calling on a Nexus 4!"); 155 | } 156 | } 157 | 158 | struct Nexus10; 159 | 160 | impl Tablet for Nexus10 { 161 | fn play_games(&self) { 162 | println("Just playing some games on my Nexus 10."); 163 | } 164 | } 165 | 166 | /* 167 | * Create GoogleFactory and implement it for our Google devices 168 | */ 169 | struct GoogleFactory; 170 | 171 | impl Factory for GoogleFactory { 172 | fn new_phone(&self) -> Nexus4 { 173 | return Nexus4; 174 | } 175 | 176 | fn new_tablet(&self) -> Nexus10 { 177 | return Nexus10; 178 | } 179 | } 180 | 181 | 182 | fn main() { 183 | // Create our two different factories 184 | let apple = AppleFactory; 185 | let google = GoogleFactory; 186 | 187 | // Both factories use the same interface, so let's just use them 188 | 189 | // Test out creating phones 190 | let phone = apple.new_phone(); 191 | phone.call(); 192 | 193 | let phone = google.new_phone(); 194 | phone.call(); 195 | 196 | // Test out creating tablets 197 | let tablet = apple.new_tablet(); 198 | tablet.play_games(); 199 | 200 | let tablet = google.new_tablet(); 201 | tablet.play_games(); 202 | } 203 | 204 | {% endhighlight %} 205 | 206 | [github]: https://github.com/jdavis/rust-design-patterns/blob/master/patterns/abstract_factory.rs 207 | -------------------------------------------------------------------------------- /docs/_posts/2013-06-11-adapter.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Adapter 4 | category: structural 5 | description: The Adapter design pattern in the Rust programming language with 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 | Also Known As: **Wrapper** 18 | 19 | ## Definition 20 | 21 | Convert the interface of a class into another interface clients expect. 22 | Adapter lets classes work together that couldn't otherwise because of 23 | incompatible interfaces. 24 | 25 | ## Diagram 26 | 27 | 34 | 35 | ## Problem 36 | 37 | Often systems of code need to interact. If this is designed from the start then 38 | there is no problem. One system defines an abstraction and the other system 39 | adds implementation for that interface. 40 | 41 | The problem arises when the system that uses the abstraction changes its 42 | requirements. If the implementation changes, then the interface is now broken. 43 | 44 | ## Wrong Solution 45 | 46 | One way to fix this is to just rewrite the system the interface to still match 47 | the new implementation. This is *can* work in some cases but depending on the 48 | size of the system it might not be feasible. 49 | 50 | ## Correct Solution 51 | 52 | The correct solution using the Adapter pattern would be to just make a middle 53 | layer that **adapts** the interface the first system expects into the new 54 | implementation. 55 | 56 | This mitigates the need to rewrite both systems yet allows flexibility in case 57 | systems continue to change. 58 | 59 | ## Example 60 | 61 | Back in the 60s there were tons of Astronatus working for NASA. At the 62 | time, all they needed to learn was how to fly NASA's ships. When ever NASA 63 | came out with a new ship, it was similar to the olds ones. This worked for 64 | decades. All was well in the galaxy. 65 | 66 | However in 2010, NASA shut down the Space Shuttle program. The Astronauts 67 | were out of jobs and started to look for new ones. Once the Astronauts realized 68 | that their space suits made for poor work attire on Earth, they knew they had to 69 | revisit the stars. So they went to the next best company to work for, SpaceX. 70 | When they got to SpaceX they realized that technology had changed quite a bit 71 | since the 60s. SpaceX realized this as well, so to compensate for the Astronauts 72 | they came up with an idea to use the Adapter pattern. 73 | 74 | The smart SpaceX engineers made a new class that just 'Adapted' the old 75 | interface of the NASA Space Shuttles to SpaceX's new rocket ships. The 76 | Astronauts now had no problem flying SpaceX's ships through the galaxy. 77 | 78 | Together the Astronauts and SpaceX were able to settle the galaxy far 79 | and wide. 80 | 81 | ### Example Diagram 82 | 83 | 89 | 90 | ### Example Code 91 | 92 | View [adapter.rs][github] on GitHub 93 | 94 | {% highlight rust %} 95 | 96 | /* 97 | * Core Trait that defines a basic Rocket Ship 98 | */ 99 | trait RocketShip { 100 | fn turn_on(&self); 101 | fn turn_off(&self); 102 | fn blast_off(&self); 103 | fn fly(&self); 104 | } 105 | 106 | /* 107 | * Basic struct for a NASA Ship 108 | */ 109 | struct NASAShip; 110 | 111 | /* 112 | * Implement RocketShip trait to add functionality to NASAShip 113 | */ 114 | impl RocketShip for NASAShip { 115 | fn turn_on(&self) { 116 | println("NASA Ship is turning on.") 117 | } 118 | 119 | fn turn_off(&self) { 120 | println("NASA Ship is turning off.") 121 | } 122 | 123 | fn blast_off(&self) { 124 | println("NASA Ship is blasting off.") 125 | } 126 | 127 | fn fly(&self) { 128 | println("NASA Ship is flying away.") 129 | } 130 | } 131 | 132 | /* 133 | * Uh oh, here is our problem. It's the amazingly advanced SpaceX ship that our 134 | * astronaut doesn't know how to pilot. 135 | */ 136 | trait SpaceXShip { 137 | fn ignition(&self); 138 | fn on(&self); 139 | fn off(&self); 140 | fn launch(&self); 141 | fn fly(&self); 142 | } 143 | 144 | /* 145 | * Basic struct for a SpaceX Dragon rocket ship 146 | */ 147 | struct SpaceXDragon; 148 | 149 | /* 150 | * Implement the SpaceX trait to add functionality to the Space X Dragon 151 | */ 152 | impl SpaceXShip for SpaceXDragon { 153 | fn ignition(&self) { 154 | println("Turning Dragon's ignition.") 155 | } 156 | 157 | fn on(&self) { 158 | println("Turning on the Dragon.") 159 | } 160 | 161 | fn off(&self) { 162 | println("Turing off the Dragon.") 163 | } 164 | 165 | fn launch(&self) { 166 | println("Launching the Dragon") 167 | } 168 | 169 | fn fly(&self) { 170 | println("The Dragon is flying away.") 171 | } 172 | } 173 | 174 | /* 175 | * Uh oh, the new SpaceXDragon doesn't implement the RocketShip interface. We 176 | * need to create an adapter that does. 177 | */ 178 | 179 | /* 180 | * Adapter to adapt anything that implements SpaceXShip to the RocketShip trait 181 | */ 182 | struct SpaceXAdapter { 183 | ship: SpaceXDragon 184 | } 185 | 186 | /* 187 | * SpaceX Adapter that adds RocketShip traits to any SpaceXShip 188 | */ 189 | impl RocketShip for SpaceXAdapter { 190 | fn turn_on(&self) { 191 | self.ship.ignition(); 192 | self.ship.on(); 193 | } 194 | 195 | fn turn_off(&self) { 196 | self.ship.off(); 197 | } 198 | 199 | fn blast_off(&self) { 200 | self.ship.launch(); 201 | } 202 | 203 | fn fly(&self) { 204 | self.ship.fly(); 205 | } 206 | } 207 | 208 | /* 209 | * Basic function to pilot ships that implement the RocketShip trait 210 | */ 211 | fn pilot(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 | --------------------------------------------------------------------------------