├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Intro.md ├── README.md ├── adapter ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── bridge ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── builder ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── chain_of_responsibility ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── command ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── composite ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── decorator ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── entity ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── facade ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── factory ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ ├── simple.rs │ └── simple2.rs ├── flyweight ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── interpreter ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── iterator ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── mediator ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── memento ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── observer ├── Cargo.toml ├── README.md └── src │ ├── bin │ └── main.rs │ ├── lib.rs │ ├── simple1.rs │ ├── simple2.rs │ └── simple3.rs ├── prototype ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── proxy ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── singleton ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── src └── main.rs ├── state ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs ├── strategy ├── Cargo.toml └── src │ ├── lib.rs │ ├── simple.rs │ └── simple2.rs ├── template ├── Cargo.toml └── src │ ├── lib.rs │ └── simple.rs └── visitor ├── Cargo.toml └── src ├── lib.rs └── simple.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | .DS_Store -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "adapter" 3 | version = "0.1.0" 4 | 5 | [[package]] 6 | name = "bitflags" 7 | version = "0.7.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | 10 | [[package]] 11 | name = "bridge" 12 | version = "0.1.0" 13 | 14 | [[package]] 15 | name = "builder" 16 | version = "0.1.0" 17 | 18 | [[package]] 19 | name = "chain_of_responsibility" 20 | version = "0.1.0" 21 | 22 | [[package]] 23 | name = "command" 24 | version = "0.1.0" 25 | 26 | [[package]] 27 | name = "composite" 28 | version = "0.1.0" 29 | 30 | [[package]] 31 | name = "decorator" 32 | version = "0.1.0" 33 | 34 | [[package]] 35 | name = "design_patterns" 36 | version = "0.1.0" 37 | dependencies = [ 38 | "adapter 0.1.0", 39 | "bridge 0.1.0", 40 | "builder 0.1.0", 41 | "chain_of_responsibility 0.1.0", 42 | "command 0.1.0", 43 | "composite 0.1.0", 44 | "decorator 0.1.0", 45 | "facade 0.1.0", 46 | "factory 0.1.0", 47 | "filter 0.1.0", 48 | "flyweight 0.1.0", 49 | "interpreter 0.1.0", 50 | "iterator 0.1.0", 51 | "mediator 0.1.0", 52 | "memento 0.1.0", 53 | "null_object 0.1.0", 54 | "observer 0.1.0", 55 | "prototype 0.1.0", 56 | "proxy 0.1.0", 57 | "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "singleton 0.1.0", 59 | "state 0.1.0", 60 | "strategy 0.1.0", 61 | "template 0.1.0", 62 | "visitor 0.1.0", 63 | ] 64 | 65 | [[package]] 66 | name = "facade" 67 | version = "0.1.0" 68 | 69 | [[package]] 70 | name = "factory" 71 | version = "0.1.0" 72 | dependencies = [ 73 | "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", 74 | ] 75 | 76 | [[package]] 77 | name = "filter" 78 | version = "0.1.0" 79 | 80 | [[package]] 81 | name = "flyweight" 82 | version = "0.1.0" 83 | 84 | [[package]] 85 | name = "fuchsia-zircon" 86 | version = "0.2.1" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | dependencies = [ 89 | "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 90 | ] 91 | 92 | [[package]] 93 | name = "fuchsia-zircon-sys" 94 | version = "0.2.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | dependencies = [ 97 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 98 | ] 99 | 100 | [[package]] 101 | name = "interpreter" 102 | version = "0.1.0" 103 | 104 | [[package]] 105 | name = "iterator" 106 | version = "0.1.0" 107 | 108 | [[package]] 109 | name = "libc" 110 | version = "0.2.32" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | 113 | [[package]] 114 | name = "mediator" 115 | version = "0.1.0" 116 | 117 | [[package]] 118 | name = "memento" 119 | version = "0.1.0" 120 | 121 | [[package]] 122 | name = "null_object" 123 | version = "0.1.0" 124 | 125 | [[package]] 126 | name = "observer" 127 | version = "0.1.0" 128 | 129 | [[package]] 130 | name = "prototype" 131 | version = "0.1.0" 132 | 133 | [[package]] 134 | name = "proxy" 135 | version = "0.1.0" 136 | 137 | [[package]] 138 | name = "rand" 139 | version = "0.3.17" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | dependencies = [ 142 | "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", 144 | ] 145 | 146 | [[package]] 147 | name = "singleton" 148 | version = "0.1.0" 149 | 150 | [[package]] 151 | name = "state" 152 | version = "0.1.0" 153 | 154 | [[package]] 155 | name = "strategy" 156 | version = "0.1.0" 157 | 158 | [[package]] 159 | name = "template" 160 | version = "0.1.0" 161 | 162 | [[package]] 163 | name = "visitor" 164 | version = "0.1.0" 165 | 166 | [metadata] 167 | "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 168 | "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" 169 | "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" 170 | "checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" 171 | "checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" 172 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "design_patterns" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | 7 | [dependencies] 8 | factory = {path = "factory"} 9 | builder = {path = "builder"} 10 | singleton = {path = "singleton"} 11 | prototype = {path = "prototype"} 12 | 13 | adapter = {path = "adapter"} 14 | bridge = {path = "bridge"} 15 | filter = {path = "filter"} 16 | composite = {path = "composite"} 17 | decorator = {path = "decorator"} 18 | facade = {path = "facade"} 19 | flyweight = {path = "flyweight"} 20 | proxy = {path = "proxy"} 21 | 22 | chain_of_responsibility = {path = "chain_of_responsibility"} 23 | command = {path = "command"} 24 | interpreter = {path = "interpreter"} 25 | iterator = {path = "iterator"} 26 | mediator = {path = "mediator"} 27 | memento = {path = "memento"} 28 | observer = {path = "observer"} 29 | state = {path = "state"} 30 | null_object = {path = "null_object"} 31 | strategy = {path = "strategy"} 32 | template = {path = "template"} 33 | visitor = {path = "visitor"} 34 | 35 | rand = "0.3.14" 36 | 37 | [workspace] -------------------------------------------------------------------------------- /Intro.md: -------------------------------------------------------------------------------- 1 | # Rust 实现Gof经典设计模式 2 | 3 | 设计模式(Design Pattern)是一套被反复使用、多数人知晓、经过分类的、代码设计经验的总结。 4 | 5 | ### 使用目的: 6 | 7 | 为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。 8 | 9 | ### 起源 10 | 11 | 与很多软件工程技术一样,模式起源于建筑领域,软件工程只有短短的几十年,与已经拥有几千年底蕴的建筑工程相比,后者有太多值得学习和借鉴的地方。 12 | 13 | 哈佛大学的建筑学博士克里斯托弗.亚历山大,是建筑学领域的模式之父。他与其研究团队用了约20年的时间,对住宅和周边环境进行了大量的调查研究,发现人们对舒适住宅和城市环境存在一些共同的认同规律,将它们归纳成253个模式。对每一个模式都从前提条件、目标问题、 解决方案三个方面进行了描述,并给出了从需求分析到结构设计再到经典实例的过程模型。 14 | 15 | 所以,对模式的定义可以抽象为在特定环境下,人们为了解决某类重复出现问题,而总结归纳出来的有效解决方案。 16 | 17 | ### 诞生 18 | 19 | GoF将模式的概念引入软件工程领域,这标志着软件模式的诞生。软件模式并非仅限于设计模式,还包括架构模式、分析模式和过程模式等,实际上,在软件开发生命周期的每一个阶段都存在着一些被认同的模式。 20 | 21 | 软件模式主要由四部分构成,包括待解决问题、约束条件、解决方案、优点。 22 | 23 | 软件模式与具体的应用领域无关,也就是说无论从事的是移动开发、桌面开发、Web开发还是嵌入式软件的开发,都可以使用软件模式。 24 | 25 | 在软件模式中,设计模式是研究最为深入的分支,它融合了众多专家的设计经验,已经在成千上万的软件中得以应用。 1995年, GoF将收集和整理好的23种设计模式汇编成了一本名叫《设计模式》的书,该书的出版也标志着设计模式正式成为面向对象版软件工程的一个重要研究分支。 26 | 27 | ## 总体来说设计模式分为三大类: 28 | 29 | - 创建模式:用来构建对象以便能从实现系统解耦。 30 | - 结构模式:用不同的对象组成大规模的对象结构。 31 | - 行为模式:用来在对象中管理算法,关系,和责任。 32 | 33 | ### 创建型模式 34 | 35 | - 工厂模式(Factory Pattern) 36 | - 抽象工厂模式(Abstract Factory Pattern) 37 | - 单例模式(Singleton Pattern) 38 | - 建造者模式(Builder Pattern) 39 | - 原型模式(Prototype Pattern) 40 | 41 | ### 结构型模式 42 | 43 | - 适配器模式(Adapter Pattern) 44 | - 桥接模式(Bridge Pattern) 45 | - 过滤器模式(Filter、Criteria Pattern) 46 | - 组合模式(Composite Pattern) 47 | - 装饰器模式(Decorator Pattern) 48 | - 外观模式(Facade Pattern) 49 | - 享元模式(Flyweight Pattern) 50 | - 代理模式(Proxy Pattern) 51 | 52 | ### 行为型模式 53 | 54 | - 责任链模式(Chain of Responsibility Pattern) 55 | - 命令模式(Command Pattern) 56 | - 解释器模式(Interpreter Pattern) 57 | - 迭代器模式(Iterator Pattern) 58 | - 中介者模式(Mediator Pattern) 59 | - 备忘录模式(Memento Pattern) 60 | - 观察者模式(Observer Pattern) 61 | - 状态模式(State Pattern) 62 | - 空对象模式(Null Object Pattern) 63 | - 策略模式(Strategy Pattern) 64 | - 模板模式(Template Pattern) 65 | - 访问者模式(Visitor Pattern) 66 | 67 | ### 另外的两种模式: 68 | 69 | - 并发模式 70 | - future 71 | - 线程池模式 72 | 73 | ## 设计模式六大原则 74 | 75 | 总原则:开闭原则(Open Close Principle) 76 | 77 | 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。想要达到这样的效果,我们需要使用接口和抽象类等。 78 | 79 | 1. 单一职责原则 (SRP:Single responsibility principle) 80 | 81 | 不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。 82 | 83 | 2. 里氏替换原则(Liskov Substitution Principle) 84 | 85 | 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。 86 | 87 | 里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。 88 | 89 | 3. 依赖倒转原则(Dependence Inversion Principle) 90 | 91 | 这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。 92 | 93 | 4. 接口隔离原则(Interface Segregation Principle) 94 | 95 | 这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。 96 | 97 | 5. 迪米特法则(最少知道原则)(Demeter Principle) 98 | 就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。 99 | 100 | 最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。 101 | 102 | 6. 合成复用原则(Composite Reuse Principle) 103 | 原则是尽量首先使用合成/聚合的方式,而不是使用继承。 104 | 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust 设计模式 2 | 3 | 本项目包括两大部分内容: 4 | 5 | - 经典设计模式(GoF)的Rust实现 6 | - 适用于Rust语言的设计模式 7 | 8 | 9 | -------------------------------------------------------------------------------- /adapter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "adapter" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /adapter/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /adapter/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Adapter { 2 | fn get_a(&self) -> usize; 3 | fn get_b(&self) -> usize; 4 | } 5 | 6 | 7 | struct ObjectX { 8 | a: usize, 9 | b: usize, 10 | } 11 | 12 | 13 | impl Adapter for ObjectX { 14 | fn get_a(&self) -> usize 15 | { 16 | self.a 17 | } 18 | 19 | fn get_b(&self) -> usize 20 | { 21 | self.b 22 | } 23 | } 24 | 25 | 26 | struct ObjectY { 27 | m: u8, 28 | n: u8, 29 | } 30 | 31 | 32 | impl Adapter for ObjectY { 33 | fn get_a(&self) -> usize 34 | { 35 | self.m as usize 36 | } 37 | 38 | fn get_b(&self) -> usize 39 | { 40 | self.n as usize 41 | } 42 | } 43 | 44 | 45 | fn main() 46 | { 47 | let obj_x = ObjectX {a: 10, b: 120}; 48 | let obj_y = ObjectY {m: 1, n: 2}; 49 | 50 | use_via_adapter(&obj_x); 51 | use_via_adapter(&obj_y); 52 | } 53 | 54 | 55 | fn use_via_adapter(adapter: &Adapter) 56 | { 57 | println!("a = {}, b = {}", adapter.get_a(), adapter.get_b()); 58 | } -------------------------------------------------------------------------------- /bridge/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bridge" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /bridge/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /bridge/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Implementor { 2 | fn decorate(&self, String) -> String; 3 | } 4 | 5 | 6 | struct ParenImpl; 7 | impl Implementor for ParenImpl { 8 | fn decorate(&self, msg: String) -> String 9 | { 10 | "(".to_string() + &msg + &")".to_string() 11 | } 12 | } 13 | 14 | 15 | struct BracketImpl; 16 | impl Implementor for BracketImpl { 17 | fn decorate(&self, msg: String) -> String 18 | { 19 | "{".to_string() + &msg + &"}".to_string() 20 | } 21 | } 22 | 23 | 24 | struct Abstraction<'a> { 25 | implementer: &'a Implementor 26 | } 27 | impl<'a> Abstraction<'a> { 28 | fn new(i: &Implementor) -> Abstraction { 29 | Abstraction { 30 | implementer: i, 31 | } 32 | } 33 | 34 | fn convert(&self, msg: String) -> String 35 | { 36 | self.implementer.decorate(msg) 37 | } 38 | } 39 | 40 | struct RefinedAbstraction<'a> { 41 | abstraction: Abstraction<'a>, 42 | } 43 | impl<'a> RefinedAbstraction<'a> { 44 | fn new(i: &Implementor) -> RefinedAbstraction { 45 | RefinedAbstraction { 46 | abstraction: Abstraction::new(i) 47 | } 48 | } 49 | 50 | fn convert(&self, msg: String) -> String 51 | { 52 | self.abstraction.convert(msg) 53 | } 54 | 55 | fn print_convert_msg(&self, msg: String) 56 | { 57 | println!("{}", self.abstraction.convert(msg)); 58 | } 59 | } 60 | 61 | 62 | fn main() 63 | { 64 | let paren_impl = &ParenImpl; 65 | let bracket_impl = &BracketImpl; 66 | 67 | let abst_p = RefinedAbstraction::new(paren_impl as &Implementor); 68 | let abst_b = RefinedAbstraction::new(bracket_impl as &Implementor); 69 | 70 | println!("{}", abst_p.convert("YOYO".to_string())); 71 | abst_b.print_convert_msg("oops".to_string()); 72 | } -------------------------------------------------------------------------------- /builder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "builder" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /builder/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /builder/src/simple.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug)] 2 | struct Person { 3 | name: String, 4 | age: u8, 5 | job: Option, 6 | } 7 | 8 | impl Person { 9 | fn new() -> Person 10 | { 11 | Person { 12 | name: Default::default(), 13 | age: Default::default(), 14 | job: None, 15 | } 16 | } 17 | 18 | fn set_name(&mut self, name: String) 19 | { 20 | self.name = name 21 | } 22 | 23 | fn set_age(&mut self, age: u8) 24 | { 25 | self.age = age 26 | } 27 | 28 | fn set_job(&mut self, job: Option) 29 | { 30 | self.job = job; 31 | } 32 | } 33 | 34 | 35 | trait Builder { 36 | fn build_name(&mut self); 37 | fn build_age(&mut self); 38 | fn build_job(&mut self); 39 | fn build(&mut self) -> Person; 40 | } 41 | 42 | 43 | struct AliceBuilder { 44 | obj: Person, 45 | } 46 | impl AliceBuilder { 47 | fn new() -> AliceBuilder 48 | { 49 | AliceBuilder { 50 | obj: Person::new(), 51 | } 52 | } 53 | } 54 | impl Builder for AliceBuilder { 55 | fn build_name(&mut self) 56 | { 57 | self.obj.set_name("Alice".to_string()) 58 | } 59 | 60 | fn build_age(&mut self) 61 | { 62 | self.obj.set_age(12) 63 | } 64 | 65 | fn build_job(&mut self) 66 | { 67 | self.obj.set_job(Some("Student".to_string())) 68 | } 69 | 70 | fn build(&mut self) -> Person 71 | { 72 | self.obj.clone() 73 | } 74 | } 75 | 76 | struct Director { 77 | builder: Box, 78 | } 79 | 80 | impl Director { 81 | fn new(b: Box) -> Director 82 | { 83 | Director { 84 | builder: b, 85 | } 86 | } 87 | 88 | fn build(&mut self) -> Person 89 | { 90 | self.builder.build_name(); 91 | self.builder.build_age(); 92 | self.builder.build_job(); 93 | self.builder.build() 94 | } 95 | } 96 | 97 | fn main() { 98 | let alice_builder = Box::new(AliceBuilder::new()) as Box; 99 | 100 | let mut director = Director::new(alice_builder); 101 | let alice = director.build(); 102 | 103 | println!("{:?}", alice); 104 | } -------------------------------------------------------------------------------- /chain_of_responsibility/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chain_of_responsibility" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /chain_of_responsibility/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chain_of_responsibility/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Cor { 2 | fn process_request(&self, &mut Request); 3 | } 4 | 5 | 6 | trait Request { 7 | fn get_level(&self) -> Level; 8 | fn get_something(&self) -> usize; 9 | } 10 | 11 | 12 | struct RequestX { 13 | level: Level, 14 | v: usize, 15 | } 16 | 17 | 18 | impl RequestX { 19 | fn new(l: Level, v: usize) -> RequestX 20 | { 21 | RequestX { 22 | level: l, 23 | v: v, 24 | } 25 | } 26 | } 27 | 28 | 29 | impl Request for RequestX { 30 | fn get_level(&self) -> Level 31 | { 32 | self.level 33 | } 34 | 35 | fn get_something(&self) -> usize 36 | { 37 | self.v 38 | } 39 | } 40 | 41 | 42 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 43 | enum Level { 44 | High, 45 | Middle, 46 | Low, 47 | } 48 | 49 | 50 | struct ImplCor { 51 | next: Option>, 52 | allowable_level: Level, 53 | } 54 | 55 | 56 | impl ImplCor { 57 | fn new(l: Level, next: Option>) -> ImplCor { 58 | ImplCor { 59 | next: next, 60 | allowable_level: l, 61 | } 62 | } 63 | } 64 | 65 | 66 | impl Cor for ImplCor { 67 | fn process_request(&self, r: &mut Request) 68 | { 69 | print!("{:?}: ", self.allowable_level); 70 | if self.allowable_level == r.get_level() { 71 | println!("Request accepted - v = {}", r.get_something()); 72 | } else { 73 | if let Some(ref next) = self.next { 74 | println!("Pass to the next"); 75 | next.process_request(r); 76 | } else { 77 | println!("Chain finished."); 78 | } 79 | } 80 | } 81 | } 82 | 83 | 84 | fn main() { 85 | let high = ImplCor::new(Level::High, None); 86 | let middle = ImplCor::new(Level::Middle, Some(Box::new(high))); 87 | let low = ImplCor::new(Level::Low, Some(Box::new(middle))); 88 | 89 | let mut r1 = RequestX::new(Level::High, 1); 90 | let mut r2 = RequestX::new(Level::Middle, 2); 91 | let mut r3 = RequestX::new(Level::Low, 3); 92 | low.process_request(&mut r3); 93 | low.process_request(&mut r2); 94 | low.process_request(&mut r1); 95 | } -------------------------------------------------------------------------------- /command/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "command" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /command/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /command/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Command { 2 | fn execute(&self, &mut T); 3 | fn undo(&self, &mut T); 4 | } 5 | 6 | 7 | struct Invoker<'a, T: 'a> { 8 | commands: Vec + 'a>>, 9 | target: &'a mut T, 10 | current_index: usize, 11 | } 12 | 13 | 14 | impl<'a, T> Invoker<'a, T> { 15 | fn new(t: &'a mut T) -> Self { 16 | Invoker { 17 | commands: Vec::new(), 18 | target: t, 19 | current_index: 0, 20 | } 21 | } 22 | 23 | 24 | fn target(&self) -> &T { 25 | self.target 26 | } 27 | 28 | fn append_command + 'a>(&mut self, c: U) { 29 | self.commands.push(Box::new(c)); 30 | } 31 | 32 | fn execute_command(&mut self) { 33 | if self.commands.len() <= self.current_index { 34 | // Nothing to do. 35 | return; 36 | } 37 | 38 | let c = &*self.commands[self.current_index]; 39 | let t = &mut *self.target; 40 | c.execute(t); 41 | 42 | self.current_index += 1; 43 | } 44 | 45 | fn execute_all_commands(&mut self) { 46 | for _ in self.current_index..self.commands.len() { 47 | self.execute_command(); 48 | } 49 | } 50 | 51 | fn undo(&mut self) { 52 | if 0 == self.current_index { 53 | return; 54 | } 55 | 56 | self.current_index -= 1; 57 | 58 | let c = &*self.commands[self.current_index]; 59 | let t = &mut *self.target; 60 | c.undo(t); 61 | } 62 | } 63 | 64 | #[derive(Debug, Eq, PartialEq)] 65 | struct Robot { 66 | x: i32, 67 | y: i32, 68 | dx: i32, 69 | dy: i32, 70 | } 71 | 72 | 73 | impl Robot { 74 | fn new() -> Robot { 75 | Robot { 76 | x: 0, 77 | y: 0, 78 | dx: 0, 79 | dy: 1, 80 | } 81 | } 82 | 83 | fn move_forward(&mut self) { 84 | self.x += self.dx; 85 | self.y += self.dy; 86 | } 87 | 88 | fn set_direction(&mut self, d: (i32, i32)) { 89 | self.dx = d.0; 90 | self.dy = d.1; 91 | } 92 | 93 | fn get_direction(&self) -> (i32, i32) { 94 | (self.dx, self.dy) 95 | } 96 | } 97 | 98 | 99 | struct CommandMoveForward; 100 | impl Command for CommandMoveForward { 101 | fn execute(&self, r: &mut Robot) { 102 | r.move_forward(); 103 | } 104 | 105 | fn undo(&self, r: &mut Robot) { 106 | let c1 = CommandTurnRight; 107 | c1.execute(r); 108 | c1.execute(r); 109 | self.execute(r); 110 | c1.execute(r); 111 | c1.execute(r); 112 | } 113 | } 114 | 115 | 116 | struct CommandTurnRight; 117 | impl Command for CommandTurnRight { 118 | fn execute(&self, r: &mut Robot) { 119 | let (dx, dy) = r.get_direction(); 120 | r.set_direction((dy, -dx)); 121 | } 122 | 123 | fn undo(&self, r: &mut Robot) { 124 | let c = CommandTurnLeft; 125 | c.execute(r); 126 | } 127 | } 128 | 129 | 130 | struct CommandTurnLeft; 131 | impl Command for CommandTurnLeft { 132 | fn execute(&self, r: &mut Robot) { 133 | let (dx, dy) = r.get_direction(); 134 | r.set_direction((-dy, dx)); 135 | } 136 | 137 | fn undo(&self, r: &mut Robot) { 138 | let c = CommandTurnRight; 139 | c.execute(r); 140 | } 141 | } 142 | 143 | 144 | fn main() { 145 | let mut r = Robot::new(); 146 | 147 | let mut invoker = Invoker::new(&mut r); 148 | assert_eq!(*invoker.target(), Robot { x: 0, y: 0, dx: 0, dy: 1, }); 149 | 150 | invoker.append_command(CommandTurnRight); 151 | invoker.append_command(CommandTurnLeft); 152 | invoker.append_command(CommandMoveForward); 153 | 154 | invoker.execute_all_commands(); 155 | assert_eq!(*invoker.target(), Robot { x: 0, y: 1, dx: 0, dy: 1, }); 156 | 157 | invoker.undo(); 158 | assert_eq!(*invoker.target(), Robot { x: 0, y: 0, dx: 0, dy: 1, }); 159 | 160 | invoker.undo(); 161 | assert_eq!(*invoker.target(), Robot { x: 0, y: 0, dx: 1, dy: 0, }); 162 | } -------------------------------------------------------------------------------- /composite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "composite" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /composite/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /composite/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Composite { 2 | fn get_name(&self) -> String; 3 | fn get_child(&self) -> Option<&Box>; 4 | fn set_child(&mut self, Box); 5 | fn print_child_name_recursive(&self); 6 | } 7 | 8 | 9 | struct File { 10 | name: String, 11 | child: Option>, 12 | } 13 | 14 | 15 | impl File { 16 | fn new(name: String) -> File 17 | { 18 | File { 19 | name: name, 20 | child: None, 21 | } 22 | } 23 | } 24 | 25 | 26 | impl Composite for File { 27 | fn get_name(&self) -> String 28 | { 29 | self.name.clone() 30 | } 31 | 32 | fn get_child(&self) -> Option<&Box> 33 | { 34 | match self.child { 35 | Some(ref x) => Some(x), 36 | None => None, 37 | } 38 | } 39 | 40 | fn set_child(&mut self, c: Box) 41 | { 42 | self.child = Some(c) 43 | } 44 | 45 | fn print_child_name_recursive(&self) 46 | { 47 | print!(" -> {}", self.get_name()); 48 | if let Some(x) = self.get_child() { 49 | x.print_child_name_recursive(); 50 | } else { 51 | println!(""); 52 | } 53 | } 54 | } 55 | 56 | 57 | // A directory is a file. 58 | struct Directory { 59 | f: File, 60 | } 61 | 62 | 63 | impl Directory { 64 | fn new(name: String) -> Directory 65 | { 66 | Directory { 67 | f: File::new(name), 68 | } 69 | } 70 | } 71 | 72 | 73 | impl Composite for Directory { 74 | fn get_name(&self) -> String 75 | { 76 | self.f.get_name() 77 | } 78 | 79 | fn get_child(&self) -> Option<&Box> 80 | { 81 | self.f.get_child() 82 | } 83 | 84 | fn set_child(&mut self, c: Box) 85 | { 86 | self.f.set_child(c) 87 | } 88 | 89 | 90 | fn print_child_name_recursive(&self) 91 | { 92 | self.f.print_child_name_recursive(); 93 | } 94 | } 95 | 96 | 97 | 98 | fn main() 99 | { 100 | let mut d1 = Directory::new("root".to_string()); 101 | let mut d2 = Directory::new("boot".to_string()); 102 | let f1 = File::new("vmlinuz-linux".to_string()); 103 | 104 | d2.set_child(Box::new(f1)); 105 | d1.set_child(Box::new(d2)); 106 | 107 | println!("Start"); 108 | d1.print_child_name_recursive(); 109 | } -------------------------------------------------------------------------------- /decorator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "decorator" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /decorator/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /decorator/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Component { 2 | fn do_something(&self); 3 | } 4 | 5 | 6 | trait Decorator: Component { 7 | fn do_something_more(&self); 8 | } 9 | 10 | 11 | struct BaseObject(usize); 12 | impl Component for BaseObject { 13 | fn do_something(&self) 14 | { 15 | println!("something: {}", self.0); 16 | } 17 | } 18 | 19 | 20 | struct DecoratedObject { 21 | base: BaseObject, 22 | more_value: usize, 23 | } 24 | 25 | impl Component for DecoratedObject { 26 | fn do_something(&self) 27 | { 28 | self.base.do_something() 29 | } 30 | } 31 | 32 | impl Decorator for DecoratedObject { 33 | fn do_something_more(&self) 34 | { 35 | println!("something more: {}", self.more_value); 36 | } 37 | } 38 | 39 | fn process(c: &Component) 40 | { 41 | c.do_something() 42 | } 43 | 44 | fn main() 45 | { 46 | let obj = BaseObject(100); 47 | process(&obj); 48 | 49 | let dobj = DecoratedObject { 50 | base: obj, 51 | more_value: 999, 52 | }; 53 | process(&dobj); 54 | dobj.do_something_more(); 55 | } -------------------------------------------------------------------------------- /entity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "entity" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /entity/README.md: -------------------------------------------------------------------------------- 1 | # HashMap中的Entity -------------------------------------------------------------------------------- /entity/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /facade/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "facade" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /facade/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /facade/src/simple.rs: -------------------------------------------------------------------------------- 1 | fn worker_a() 2 | { 3 | println!("hoge"); 4 | } 5 | 6 | 7 | fn worker_b() 8 | { 9 | println!("huga"); 10 | } 11 | 12 | 13 | fn worker_c() 14 | { 15 | println!("piyo"); 16 | } 17 | 18 | 19 | struct Facade; 20 | impl Facade { 21 | fn facade_method(&self) 22 | { 23 | worker_a(); 24 | worker_b(); 25 | worker_c(); 26 | } 27 | } 28 | 29 | 30 | fn main() 31 | { 32 | let f = Facade; 33 | f.facade_method(); 34 | } -------------------------------------------------------------------------------- /factory/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "factory" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | rand = "0.3.14" -------------------------------------------------------------------------------- /factory/README.md: -------------------------------------------------------------------------------- 1 | # 工厂模式 2 | 3 | 4 | 5 | 6 | # 抽象工厂模式 7 | 8 | -------------------------------------------------------------------------------- /factory/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add_one(x: i32) -> i32 { 2 | x + 1 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | assert_eq!(3, add_one(2)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /factory/src/simple.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 抽象工厂模式 3 | */ 4 | 5 | trait AbstractFactory<'a> { 6 | fn create_product_x(&self) -> Box; 7 | fn create_product_y(&self) -> Box; 8 | } 9 | 10 | 11 | trait ProductX { 12 | fn get_value(&self) -> String; 13 | } 14 | 15 | 16 | trait ProductY { 17 | fn get_value(&self) -> String; 18 | } 19 | 20 | 21 | struct ConcreteProductX(String); 22 | impl ConcreteProductX { 23 | fn new(msg: String) -> ConcreteProductX { 24 | ConcreteProductX(msg + &" ProductX".to_string()) 25 | } 26 | } 27 | 28 | 29 | impl ProductX for ConcreteProductX { 30 | fn get_value(&self) -> String 31 | { 32 | self.0.clone() 33 | } 34 | } 35 | 36 | 37 | struct ConcreteProductY(String); 38 | impl ConcreteProductY { 39 | fn new(msg: String) -> ConcreteProductY { 40 | ConcreteProductY(msg + &" ProductY".to_string()) 41 | } 42 | } 43 | 44 | 45 | impl ProductY for ConcreteProductY { 46 | fn get_value(&self) -> String 47 | { 48 | self.0.clone() 49 | } 50 | } 51 | 52 | 53 | struct ConcreteFactoryA; 54 | impl<'a> AbstractFactory<'a> for ConcreteFactoryA { 55 | fn create_product_x(&self) -> Box 56 | { 57 | Box::new(ConcreteProductX::new("FactoryA".to_string())) as Box 58 | } 59 | 60 | fn create_product_y(&self) -> Box 61 | { 62 | Box::new(ConcreteProductY::new("FactoryA".to_string())) as Box 63 | } 64 | } 65 | 66 | 67 | struct ConcreteFactoryB; 68 | impl<'a> AbstractFactory<'a> for ConcreteFactoryB { 69 | fn create_product_x(&self) -> Box 70 | { 71 | Box::new(ConcreteProductX::new("FactoryB".to_string())) as Box 72 | } 73 | 74 | fn create_product_y(&self) -> Box 75 | { 76 | Box::new(ConcreteProductY::new("FactoryB".to_string())) as Box 77 | } 78 | } 79 | 80 | 81 | 82 | enum FactoryID { 83 | A, 84 | B, 85 | } 86 | 87 | fn create_factory<'a>(id: FactoryID) -> Box + 'a> 88 | { 89 | match id { 90 | FactoryID::A => Box::new(ConcreteFactoryA), 91 | FactoryID::B => Box::new(ConcreteFactoryB), 92 | } 93 | } 94 | 95 | 96 | 97 | fn main() 98 | { 99 | let factory_a = create_factory(FactoryID::A); 100 | let a_x = factory_a.create_product_x(); 101 | let a_y = factory_a.create_product_y(); 102 | println!("{}", a_x.get_value()); 103 | println!("{}", a_y.get_value()); 104 | 105 | let factory_b = create_factory(FactoryID::B); 106 | let b_x = factory_b.create_product_x(); 107 | let b_y = factory_b.create_product_y(); 108 | println!("{}", b_x.get_value()); 109 | println!("{}", b_y.get_value()); 110 | } 111 | 112 | -------------------------------------------------------------------------------- /factory/src/simple2.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 工厂模式 3 | */ 4 | 5 | trait Product { 6 | fn convert(&self, String) -> String; 7 | } 8 | 9 | 10 | trait Factory { 11 | fn create_product(&self) -> Box; 12 | fn convert(&self, s: String) -> String 13 | { 14 | self.create_product().convert(s) 15 | } 16 | } 17 | 18 | 19 | struct ConcreteProductX; 20 | impl Product for ConcreteProductX { 21 | fn convert(&self, s: String) -> String 22 | { 23 | s.to_uppercase() 24 | } 25 | } 26 | 27 | 28 | struct ConcreteFactoryX; 29 | impl Factory for ConcreteFactoryX { 30 | fn create_product(&self) -> Box 31 | { 32 | Box::new(ConcreteProductX) as Box 33 | } 34 | } 35 | 36 | 37 | fn main() 38 | { 39 | let f = ConcreteFactoryX; 40 | println!("{}", f.convert("hogehoge piyopiyo".to_string())) 41 | } -------------------------------------------------------------------------------- /flyweight/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flyweight" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /flyweight/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /flyweight/src/simple.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | 4 | #[derive(Debug)] 5 | struct Object(String, usize); 6 | 7 | 8 | struct Fryweight { 9 | pool: HashMap, 10 | counter: usize, 11 | } 12 | 13 | 14 | impl Fryweight { 15 | fn new() -> Fryweight 16 | { 17 | Fryweight { 18 | pool: HashMap::new(), 19 | counter: 0, 20 | } 21 | } 22 | 23 | fn obtain_object(&mut self, key: String) -> &mut Object 24 | { 25 | if self.pool.contains_key(&key) { 26 | return self.pool.get_mut(&key).unwrap() 27 | } 28 | 29 | self.pool.insert(key.clone(), Object(key.clone(), self.counter)); 30 | self.counter += 1; 31 | self.obtain_object(key) 32 | } 33 | } 34 | 35 | 36 | fn main() 37 | { 38 | let mut fryweight = Fryweight::new(); 39 | 40 | { 41 | let o1 = fryweight.obtain_object("hoge".to_string()); 42 | println!("{:?}", o1); 43 | o1.1 = 567; 44 | } 45 | 46 | let o2 = fryweight.obtain_object("hoge".to_string()); 47 | println!("{:?}", o2); 48 | } -------------------------------------------------------------------------------- /interpreter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "interpreter" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /interpreter/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /interpreter/src/simple.rs: -------------------------------------------------------------------------------- 1 | struct Interpreter; 2 | 3 | impl Interpreter { 4 | fn parse_and_execute(s: String) 5 | { 6 | let mut s = s.clone(); 7 | if let Some(i) = s.find(' ') { 8 | let word = s.split_off(i); 9 | let times = s.parse::().unwrap(); 10 | for _ in 0..times { 11 | print!("{} ", word); 12 | } 13 | println!(""); 14 | } 15 | } 16 | } 17 | 18 | 19 | fn main() 20 | { 21 | Interpreter::parse_and_execute("10 hey guys !".to_string()); 22 | } -------------------------------------------------------------------------------- /iterator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iterator" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /iterator/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /iterator/src/simple.rs: -------------------------------------------------------------------------------- 1 | struct Container { 2 | buf: Vec, 3 | index: usize, 4 | } 5 | 6 | 7 | impl Container { 8 | fn new() -> Container 9 | { 10 | Container { 11 | buf: Vec::new(), 12 | index: 0, 13 | } 14 | } 15 | 16 | fn add(&mut self, t: T) 17 | { 18 | self.buf.push(t); 19 | } 20 | } 21 | 22 | 23 | impl Iterator for Container { 24 | type Item = T; 25 | 26 | fn next(&mut self) -> Option 27 | { 28 | match self.index < self.buf.len() { 29 | true => { 30 | let t = Some(self.buf[self.index]); 31 | self.index += 1; 32 | t 33 | } 34 | false => None, 35 | } 36 | } 37 | } 38 | 39 | 40 | fn main() 41 | { 42 | let mut c: Container = Container::::new(); 43 | c.add(10); 44 | c.add(20); 45 | c.add(30); 46 | 47 | for i in c { 48 | println!("{}", i); 49 | } 50 | } -------------------------------------------------------------------------------- /mediator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mediator" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /mediator/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /mediator/src/simple.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | 4 | struct Mediator { 5 | colleagues: HashMap, 6 | } 7 | 8 | 9 | impl Mediator { 10 | fn new() -> Mediator { 11 | Mediator { 12 | colleagues: HashMap::new(), 13 | } 14 | } 15 | 16 | fn add_colleague(&mut self, c: Colleague) 17 | { 18 | self.colleagues.insert(c.0.clone(), c); 19 | } 20 | 21 | fn consult_to(&self, s: &String, msg: String) 22 | { 23 | self.colleagues.get(s).unwrap().receive_msg(msg); 24 | } 25 | 26 | fn get(&self, s: &String) -> &Colleague 27 | { 28 | self.colleagues.get(s).unwrap() 29 | } 30 | } 31 | 32 | 33 | struct Colleague(String); 34 | impl Colleague { 35 | fn new(s: &String) -> Colleague 36 | { 37 | Colleague(s.clone()) 38 | } 39 | 40 | fn send_msg(&self, m: &Mediator, to: &String, msg: String) 41 | { 42 | m.consult_to(to, msg); 43 | } 44 | 45 | fn receive_msg(&self, msg: String) 46 | { 47 | println!("{} gets {}", self.0, msg); 48 | } 49 | } 50 | 51 | 52 | fn main() 53 | { 54 | let mut mediator = Mediator::new(); 55 | let key1 = "Hoge".to_string(); 56 | let c1 = Colleague::new(&key1); 57 | let key2 = "Piyo".to_string(); 58 | let c2 = Colleague::new(&key2); 59 | 60 | mediator.add_colleague(c1); 61 | mediator.add_colleague(c2); 62 | 63 | let c1 = mediator.get(&key1); 64 | c1.send_msg(&mediator, &key2, "hi from Hoge".to_string()); 65 | let c2 = mediator.get(&key2); 66 | c2.send_msg(&mediator, &key1, "hi from Piyo".to_string()); 67 | } -------------------------------------------------------------------------------- /memento/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "memento" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /memento/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /memento/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Originator { 2 | fn generate_memento(&self) -> Box; 3 | fn restore_from_memento(&mut self, &Memento); 4 | } 5 | 6 | 7 | trait Caretaker { 8 | fn add_memento(&mut self, Box); 9 | fn get_memento(&mut self, usize) -> &Memento; 10 | } 11 | 12 | 13 | trait Memento { 14 | fn get_value(&self) -> usize; 15 | } 16 | 17 | 18 | #[derive(Debug)] 19 | struct OriginatorX(usize); 20 | impl Originator for OriginatorX { 21 | fn generate_memento(&self) -> Box 22 | { 23 | Box::new(MementoX(self.0)) 24 | } 25 | 26 | fn restore_from_memento(&mut self, m: &Memento) 27 | { 28 | self.0 = m.get_value() 29 | } 30 | } 31 | 32 | 33 | struct MementoX(usize); 34 | impl Memento for MementoX { 35 | fn get_value(&self) -> usize 36 | { 37 | self.0 38 | } 39 | } 40 | 41 | 42 | struct CaretakerX { 43 | history: Vec>, 44 | } 45 | 46 | 47 | impl CaretakerX { 48 | fn new() -> CaretakerX { 49 | CaretakerX { 50 | history: Vec::new(), 51 | } 52 | } 53 | } 54 | 55 | 56 | impl Caretaker for CaretakerX { 57 | fn add_memento(&mut self, m: Box) 58 | { 59 | self.history.push(m) 60 | } 61 | 62 | fn get_memento(&mut self, index: usize) -> &Memento 63 | { 64 | & *self.history[index] 65 | } 66 | } 67 | 68 | fn main() 69 | { 70 | let mut caretaker = CaretakerX::new(); 71 | let mut originator = OriginatorX(10); 72 | 73 | caretaker.add_memento(originator.generate_memento()); 74 | println!("{:?}", originator); 75 | originator.0 = 99; 76 | println!("{:?}", originator); 77 | originator.restore_from_memento(caretaker.get_memento(0)); 78 | println!("{:?}", originator); 79 | } -------------------------------------------------------------------------------- /observer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "observer" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [[bin]] 7 | name = "observer" 8 | path = "src/bin/main.rs" 9 | 10 | [dependencies] 11 | -------------------------------------------------------------------------------- /observer/README.md: -------------------------------------------------------------------------------- 1 | # 观察者模式(Observer pattern) 2 | 3 | 观察者模式用于建立这样一种依赖关系:当某个对象发生改变的时候,将自动通知其他对象,其他对象将做出相应的反应。发生改变的对象称为观察目标,而被通知的对象称为观察者。一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。也被称为发布订阅模式(Pub/Sub)、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。 4 | 5 | 观察者模式属于行为型模式。 6 | 7 | ## 模式结构 8 | 9 | 包含角色: 10 | 11 | - 抽象目标(Subject) 12 | - 具体目标 13 | - 抽象观察者(Observer) 14 | - 具体观察者 15 | 16 | 17 | ### 优点 18 | 19 | 观察者模式的优点 20 | 21 | - 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。 22 | - 观察者模式在观察目标和观察者之间建立一个抽象的耦合。 23 | - 观察者模式支持广播通信。 24 | - 观察者模式符合“开闭原则”的要求。 25 | 26 | ### 缺点 27 | 28 | 观察者模式的缺点 29 | 30 | - 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 31 | - 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 32 | - 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。 33 | 34 | 35 | ### 适用环境 36 | 37 | 在以下情况下可以使用观察者模式: 38 | 39 | - 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。 40 | - 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。 41 | - 一个对象必须通知其他对象,而并不知道这些对象是谁。 42 | 43 | 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。 44 | 45 | ### 模式应用 46 | 47 | 观察者模式在软件开发中应用非常广泛,如某电子商务网站可以在执行发送操作后给用户多个发送商品打折信息,某团队战斗游戏中某队友牺牲将给所有成员提示等等,凡是涉及到一对一或者一对多的对象交互场景都可以使用观察者模式。 48 | 49 | ### 实例说明 50 | 51 | 利用观察者模式实现事件驱动的日志,用于记录tcp连接事件。 52 | 53 | 定义Events trait来抽象TCP连接中的事件接口: 54 | 55 | - on_connect 56 | - on_error 57 | - on_read 58 | - on_shutdown 59 | - on_pre_read 60 | - on_post_read 61 | 62 | 定义结构体Logger,为其实现Events,当事件发生的时候,会打印相关信息。 63 | 64 | 接下来使用HttpClient结构体来执行网络调用,并在事件发生时,通知其注册的hooks(观察者)。 65 | 66 | main函数中,使用httpbin.org网站来验证请求并打印数据。 67 | -------------------------------------------------------------------------------- /observer/src/bin/main.rs: -------------------------------------------------------------------------------- 1 | extern crate observer; 2 | 3 | use observer::HttpClient; 4 | use observer::Logger; 5 | 6 | fn main() { 7 | let mut http_stream = HttpClient::new("httpbin.org", 80); 8 | http_stream.add_events_hook(Logger); 9 | http_stream.get("/ip"); 10 | // http_stream.get("/uuid"); 11 | } -------------------------------------------------------------------------------- /observer/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::str; 3 | use std::error::Error; 4 | use std::io::{Read, Write}; 5 | use std::net::TcpStream; 6 | 7 | #[allow(unused_variables)] 8 | pub trait Events { 9 | fn on_connect(&self, host: &str, port: i32) {} 10 | fn on_error(&self, err: &str) {} 11 | fn on_read(&self, resp: &[u8]) {} 12 | fn on_shutdown(&self) {} 13 | fn on_pre_read(&self) {} 14 | fn on_post_read(&self) {} 15 | } 16 | 17 | pub struct Logger; 18 | 19 | impl Events for Logger { 20 | fn on_connect(&self, host: &str, port: i32) { 21 | println!("Connected to {} on port {}", host, port); 22 | } 23 | 24 | fn on_error(&self, err: &str) { 25 | println!("error: {}", err); 26 | } 27 | 28 | fn on_read(&self, resp: &[u8]) { 29 | print!("{}", str::from_utf8(resp).unwrap()); 30 | } 31 | 32 | fn on_shutdown(&self) { 33 | println!("Connection closed."); 34 | } 35 | 36 | fn on_pre_read(&self) { 37 | println!("Receiving content:\n"); 38 | } 39 | 40 | fn on_post_read(&self) { 41 | println!("\nFinished receiving content.") 42 | } 43 | } 44 | 45 | pub struct HttpClient { 46 | host: String, 47 | port: i32, 48 | hooks: Vec>, 49 | } 50 | 51 | impl HttpClient { 52 | pub fn new(host: &str, port: i32) -> Self { 53 | Self { 54 | host: host.to_owned(), 55 | port: port, 56 | hooks: Vec::new(), 57 | } 58 | } 59 | 60 | pub fn add_events_hook(&mut self, hook: E) { 61 | self.hooks.push(Box::new(hook)); 62 | } 63 | 64 | pub fn get(&self, endpoint: &str) { 65 | let cmd = format!("GET {} HTTP/1.1\r\nHost: {}\r\n\r\n", endpoint, self.host).into_bytes(); 66 | let mut socket = self.connect().unwrap(); 67 | socket.write(cmd.as_slice()).unwrap(); 68 | socket.flush().unwrap(); 69 | for hook in &self.hooks { 70 | hook.on_pre_read(); 71 | } 72 | loop { 73 | let mut buf = vec![0; 512usize]; 74 | let cnt = socket.read(&mut buf[..]).unwrap(); 75 | buf.truncate(cnt); 76 | if !buf.is_empty() { 77 | for hook in &self.hooks { 78 | hook.on_read(buf.as_slice()); 79 | } 80 | } else { 81 | for hook in &self.hooks { 82 | hook.on_post_read(); 83 | } 84 | break; 85 | } 86 | } 87 | for hook in &self.hooks { 88 | hook.on_shutdown(); 89 | } 90 | 91 | } 92 | 93 | pub fn connect(&self) -> io::Result{ 94 | let addr = format!("{}:{}", self.host, self.port); 95 | match TcpStream::connect(addr) { 96 | Ok(stream) => { 97 | for hook in &self.hooks { 98 | hook.on_connect(&self.host, self.port); 99 | } 100 | Ok(stream) 101 | }, 102 | Err(error) => { 103 | for hook in &self.hooks { 104 | hook.on_error(error.description()); 105 | } 106 | Err(error) 107 | }, 108 | } 109 | 110 | } 111 | } 112 | 113 | 114 | #[cfg(test)] 115 | mod tests { 116 | #[test] 117 | fn it_works() { 118 | assert_eq!(2 + 2, 4); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /observer/src/simple1.rs: -------------------------------------------------------------------------------- 1 | // Observer 2 | trait Observer { 3 | fn update(&self); 4 | } 5 | 6 | // Observable memorizes all Observers and send notifications 7 | trait Observable<'a, T: Observer> { 8 | fn add_observer(&mut self, observer: &'a T); 9 | fn delete_observer(&mut self, observer: &'a T); 10 | fn notify_observers(&self); 11 | } 12 | 13 | // Define Observer and Observable 14 | struct Display { 15 | name: String, 16 | } 17 | struct Weather<'a, T:'a> { 18 | temperature: f64, 19 | observers: Vec<&'a T> 20 | } 21 | impl<'a> Weather<'a, Display> { 22 | fn set_temperature(&mut self, temperature: f64) { 23 | self.temperature = temperature; 24 | self.notify_observers(); 25 | } 26 | } 27 | /* 28 | * Traits implementations 29 | */ 30 | //impl Observer for Display { 31 | impl Observer for Display { 32 | fn update(&self) { 33 | println!("Display {} updated!", self.name); 34 | } 35 | } 36 | impl Display { 37 | fn new(name: String) -> Display { 38 | Display{name: name} 39 | } 40 | } 41 | impl std::cmp::PartialEq for Display { 42 | fn eq(&self, other: &Display) -> bool { 43 | self.name == other.name 44 | } 45 | } 46 | impl std::fmt::Display for Display { 47 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 48 | write!(f, "Display {}", self.name) 49 | } 50 | } 51 | impl<'a, T: Observer+PartialEq+std::fmt::Display> Observable<'a, T> for Weather<'a, T> { 52 | fn add_observer(&mut self, observer: &'a T) { 53 | println!("add_observer({});", observer); 54 | self.observers.push(observer); 55 | } 56 | fn delete_observer(&mut self, observer: &'a T) { 57 | let mut index = 0; 58 | let mut found = false; 59 | for &obs in self.observers.iter() { 60 | if obs == observer { 61 | println!("delete_observer({});", observer); 62 | found = true; 63 | break; 64 | } 65 | index += 1; 66 | } 67 | if found { 68 | self.observers.remove(index); 69 | } 70 | } 71 | fn notify_observers(&self) { 72 | for &observer in self.observers.iter() { 73 | observer.update(); 74 | } 75 | } 76 | } 77 | 78 | fn main() { 79 | // reference must be valid for the block 80 | // so all bindings display must exist before weather 81 | let display = Display::new("Desktop".to_string()); 82 | let display2 = Display::new("Desktop2".to_string()); 83 | let mut weather = Weather{temperature: 19.0, observers: Vec::new()}; 84 | weather.add_observer(&display); 85 | weather.add_observer(&display2); 86 | weather.set_temperature(20.0); 87 | weather.delete_observer(&display2); 88 | weather.set_temperature(21.0); 89 | } -------------------------------------------------------------------------------- /observer/src/simple2.rs: -------------------------------------------------------------------------------- 1 | /// the observable type 2 | pub trait Observable { 3 | fn register(&mut self, observer: Box>); 4 | } 5 | 6 | pub trait Observer { 7 | type Item; 8 | 9 | fn notify(&self, val: &Self::Item); 10 | } 11 | 12 | 13 | /// the actual structs which implement the Observable and Observer 14 | /// traits 15 | 16 | /// the specific Observable 17 | pub struct EvenCounter { 18 | counter: u32, 19 | observers: Vec>>, 20 | } 21 | 22 | impl EvenCounter { 23 | pub fn new() -> Self { 24 | EvenCounter { 25 | counter: 0u32, 26 | observers: Vec::new(), 27 | } 28 | } 29 | 30 | pub fn run(&mut self) { 31 | loop { 32 | use std::thread; 33 | use std::time::Duration; 34 | 35 | thread::sleep(Duration::from_millis(self.get_rand_duration())); 36 | 37 | self.counter += 1; 38 | 39 | if self.counter % 2 == 0 { 40 | for observer in self.observers.iter() { 41 | observer.notify(&self.counter); 42 | } 43 | } 44 | } 45 | } 46 | 47 | fn get_rand_duration(&self) -> u64 { 48 | if cfg!(target_os = "windows") { 49 | 500u64 50 | } else { 51 | use std::process::Command; 52 | use std::str::FromStr; 53 | 54 | let rand_cmd = Command::new("sh") 55 | .arg("-c") 56 | .arg("echo $(( $RANDOM%1000 + 1 ))") 57 | .output() 58 | .expect("failed to get OS RNG"); 59 | 60 | u64::from_str(&String::from_utf8(rand_cmd.stdout).unwrap().trim()).unwrap() 61 | } 62 | } 63 | } 64 | 65 | impl Observable for EvenCounter { 66 | fn register(&mut self, observer: Box>) { 67 | self.observers.push(observer); 68 | } 69 | } 70 | 71 | /// the specific Observer type 72 | pub struct EvenObserver { 73 | name: String, 74 | } 75 | 76 | impl EvenObserver { 77 | pub fn new(name: String) -> Self { 78 | EvenObserver { name: name } 79 | } 80 | 81 | fn name(&self) -> &str { 82 | &self.name 83 | } 84 | } 85 | 86 | impl Observer for EvenObserver { 87 | type Item = u32; 88 | 89 | fn notify(&self, val: &Self::Item) { 90 | println!("{} got {}", self.name(), val); 91 | } 92 | } 93 | 94 | fn main() { 95 | let mut foo = EvenCounter::new(); 96 | let (bar, baz, quux) = (Box::new(EvenObserver::new("bar".to_string())), 97 | Box::new(EvenObserver::new("baz".to_string())), 98 | Box::new(EvenObserver::new("quux".to_string()))); 99 | 100 | foo.register(bar); 101 | foo.register(baz); 102 | foo.register(quux); 103 | 104 | foo.run(); 105 | } 106 | -------------------------------------------------------------------------------- /observer/src/simple3.rs: -------------------------------------------------------------------------------- 1 | trait Subject { 2 | fn notify_observers(&self, &T); 3 | fn register_observer(&mut self, Box>) -> usize; 4 | fn unregister_observer(&mut self, usize); 5 | } 6 | 7 | 8 | trait Observer { 9 | fn on_notify(&self, &T); 10 | } 11 | 12 | 13 | #[derive(Debug, Clone)] 14 | struct EventObject(usize); 15 | 16 | 17 | struct SubjectX { 18 | observers: Vec<(bool, Box>)>, 19 | } 20 | 21 | 22 | impl SubjectX { 23 | fn new() -> SubjectX 24 | { 25 | SubjectX { 26 | observers: Vec::new(), 27 | } 28 | } 29 | } 30 | 31 | 32 | impl Subject for SubjectX { 33 | fn notify_observers(&self, e: &EventObject) 34 | { 35 | for observer in self.observers.iter() { 36 | if observer.0 { 37 | observer.1.on_notify(e); 38 | } 39 | } 40 | } 41 | 42 | fn register_observer(&mut self, o: Box>) -> usize 43 | { 44 | self.observers.push((true, o)); 45 | self.observers.len() - 1 46 | } 47 | 48 | fn unregister_observer(&mut self, i: usize) 49 | { 50 | self.observers[i].0 = false 51 | } 52 | } 53 | 54 | 55 | struct ObserverX(usize); 56 | impl Observer for ObserverX { 57 | fn on_notify(&self, e: &EventObject) 58 | { 59 | println!("ObserverX {} Get {:?}", self.0, e); 60 | } 61 | } 62 | 63 | 64 | fn main() 65 | { 66 | let mut subject = SubjectX::new(); 67 | subject.register_observer(Box::new(ObserverX(1))); 68 | subject.register_observer(Box::new(ObserverX(2))); 69 | subject.register_observer(Box::new(ObserverX(3))); 70 | 71 | subject.notify_observers(&EventObject(100)); 72 | subject.notify_observers(&EventObject(20)); 73 | } -------------------------------------------------------------------------------- /prototype/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prototype" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /prototype/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /prototype/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Prototype: Clone { 2 | fn set_x(&mut self, usize); 3 | fn set_y(&mut self, usize); 4 | } 5 | 6 | #[derive(Debug, Clone)] 7 | struct Object { 8 | x: usize, 9 | y: usize, 10 | } 11 | 12 | impl Object { 13 | fn new() -> Object 14 | { 15 | Object { 16 | x: 100, 17 | y: 200, 18 | } 19 | } 20 | } 21 | 22 | impl Prototype for Object { 23 | fn set_x(&mut self, x: usize) 24 | { 25 | self.x = x; 26 | } 27 | 28 | fn set_y(&mut self, y: usize) 29 | { 30 | self.y = y; 31 | } 32 | } 33 | 34 | 35 | fn main() 36 | { 37 | let origin = Object::new(); 38 | let mut obj = origin.clone(); 39 | obj.set_x(123); 40 | 41 | println!("origin = {:?}", origin); 42 | println!("obj = {:?}", obj); 43 | } -------------------------------------------------------------------------------- /proxy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "proxy" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /proxy/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /proxy/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Subject { 2 | fn get_something(&mut self) -> usize; 3 | } 4 | 5 | struct RealSubject(usize); 6 | impl RealSubject { 7 | fn new() -> RealSubject 8 | { 9 | let mut rs = RealSubject(0); 10 | rs.load_something(); 11 | 12 | rs 13 | } 14 | 15 | fn load_something(&mut self) 16 | { 17 | println!("Try to load something, it is extremely heavy."); 18 | 19 | self.0 = 100; 20 | } 21 | } 22 | 23 | impl Subject for RealSubject { 24 | fn get_something(&mut self) -> usize 25 | { 26 | self.0 27 | } 28 | } 29 | 30 | struct Proxy(Option); 31 | impl Proxy { 32 | fn new() -> Proxy 33 | { 34 | Proxy(None) 35 | } 36 | } 37 | impl Subject for Proxy { 38 | fn get_something(&mut self) -> usize 39 | { 40 | match self.0 { 41 | Some(ref mut something) => { 42 | something.get_something() 43 | }, 44 | None => { 45 | let mut rs = RealSubject::new(); 46 | let x = rs.get_something(); 47 | self.0 = Some(rs); 48 | x 49 | } 50 | } 51 | } 52 | } 53 | 54 | 55 | fn main() 56 | { 57 | let mut rs = RealSubject::new(); 58 | println!("Create RealSubject"); 59 | println!("{}", rs.get_something()); 60 | 61 | let mut p1 = Proxy::new(); 62 | println!("Create Proxy Object"); 63 | let mut p2 = Proxy::new(); 64 | println!("Create Proxy Object"); 65 | println!("{}", p1.get_something()); 66 | println!("{}", p2.get_something()); 67 | } -------------------------------------------------------------------------------- /singleton/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "singleton" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /singleton/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /singleton/src/simple.rs: -------------------------------------------------------------------------------- 1 | static mut SINGLETON_G: Option = None; 2 | 3 | #[derive(Debug)] 4 | struct Singleton { 5 | v: usize, 6 | } 7 | 8 | impl Singleton { 9 | fn new() -> &'static mut Singleton 10 | { 11 | unsafe { 12 | match SINGLETON_G { 13 | Some(ref mut obj) => obj, 14 | None => { 15 | SINGLETON_G = Some(Singleton{v: 100}); 16 | Singleton::new() 17 | } 18 | } 19 | } 20 | } 21 | } 22 | 23 | 24 | fn main() 25 | { 26 | let s1 = Singleton::new(); 27 | let s2 = Singleton::new(); 28 | println!("{:?}", s1); 29 | println!("{:?}", s2); 30 | 31 | s1.v = 999; 32 | println!("{:?}", s1); 33 | println!("{:?}", s2); 34 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate factory; 2 | extern crate rand; 3 | 4 | fn main() { 5 | let num = 10; 6 | println!("Hello, world! {} plus one is {}!", 7 | num, 8 | factory::add_one(num)); 9 | } 10 | -------------------------------------------------------------------------------- /state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "state" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /state/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /state/src/simple.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | 4 | #[derive(Debug, Eq, PartialEq, Hash)] 5 | enum StateDice { 6 | PowerOn, 7 | StopDice, 8 | PowerOff 9 | } 10 | 11 | 12 | trait State { 13 | fn on_press_button(&self, &mut StateContext); 14 | } 15 | 16 | struct StatePowerOn; 17 | impl State for StatePowerOn { 18 | fn on_press_button(&self, context: &mut StateContext) 19 | { 20 | // Something to do for turning on the dice. 21 | println!("Power on and Shake the dice."); 22 | 23 | context.set_state(StateDice::StopDice); 24 | } 25 | } 26 | 27 | struct StateStop; 28 | impl State for StateStop { 29 | fn on_press_button(&self, context: &mut StateContext) 30 | { 31 | // Something to do for turning on the dice. 32 | println!("Stopping the dice."); 33 | 34 | context.set_dice_number(4); 35 | 36 | context.set_state(StateDice::PowerOff); 37 | } 38 | } 39 | 40 | struct StatePowerOff; 41 | impl State for StatePowerOff { 42 | fn on_press_button(&self, context: &mut StateContext) 43 | { 44 | // Something to do for turning on the dice. 45 | println!("Power off."); 46 | 47 | context.set_state(StateDice::PowerOn); 48 | } 49 | } 50 | 51 | 52 | #[derive(Debug)] 53 | struct StateContext { 54 | number: Option, 55 | current_state: StateDice, 56 | } 57 | 58 | impl StateContext { 59 | fn new() -> StateContext 60 | { 61 | StateContext { 62 | number: None, 63 | current_state: StateDice::PowerOn, 64 | } 65 | } 66 | 67 | fn set_state(&mut self, s: StateDice) 68 | { 69 | self.current_state = s; 70 | } 71 | 72 | fn set_dice_number(&mut self, n :u8) 73 | { 74 | self.number = Some(n) 75 | } 76 | 77 | fn press_button<'a>(&mut self, hmap: &HashMap>) 78 | { 79 | let b = hmap.get(&self.current_state).unwrap(); 80 | b.on_press_button(self); 81 | } 82 | } 83 | 84 | 85 | fn main() { 86 | let mut hmap = HashMap::new(); 87 | hmap.insert(StateDice::PowerOn, Box::new(StatePowerOn) as Box); 88 | hmap.insert(StateDice::StopDice, Box::new(StateStop) as Box); 89 | hmap.insert(StateDice::PowerOff, Box::new(StatePowerOff) as Box); 90 | let hmap = &hmap; 91 | 92 | let mut context = StateContext::new(); 93 | context.press_button(hmap); 94 | println!("{:?}", context); 95 | context.press_button(hmap); 96 | println!("{:?}", context); 97 | context.press_button(hmap); 98 | println!("{:?}", context); 99 | } -------------------------------------------------------------------------------- /strategy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "strategy" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /strategy/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /strategy/src/simple.rs: -------------------------------------------------------------------------------- 1 | //! Each action is encapsulated into a struct with the trait Command 2 | //! where only the method `execute()` is run. 3 | trait Command { 4 | fn execute(&self); 5 | } 6 | 7 | // Use a Null struct to initialize the remote control. 8 | struct NullCommand; 9 | impl NullCommand { 10 | fn new() -> NullCommand { 11 | NullCommand 12 | } 13 | } 14 | impl Command for NullCommand { 15 | fn execute(&self) { 16 | println!("Nothing to do!"); 17 | } 18 | } 19 | 20 | // The object to handle: a light 21 | #[derive(Copy, Clone)] 22 | struct Light; 23 | impl Light { 24 | fn new() -> Light { 25 | Light 26 | } 27 | fn on(&self) { 28 | println!("Light is on"); 29 | } 30 | fn off(&self) { 31 | println!("Light is off"); 32 | } 33 | } 34 | 35 | // The first command on the object: light on 36 | struct LightOnCommand { 37 | light: Light, 38 | } 39 | impl LightOnCommand { 40 | fn new(light: Light) -> LightOnCommand { 41 | LightOnCommand { light: light } 42 | } 43 | } 44 | impl Command for LightOnCommand { 45 | fn execute(&self) { 46 | self.light.on(); 47 | } 48 | } 49 | 50 | // The second command on the object: light off 51 | struct LightOffCommand { 52 | light: Light, 53 | } 54 | impl LightOffCommand { 55 | fn new(light: Light) -> LightOffCommand { 56 | LightOffCommand { light: light } 57 | } 58 | } 59 | impl Command for LightOffCommand { 60 | fn execute(&self) { 61 | self.light.off(); 62 | } 63 | } 64 | 65 | // The command will be launched by a remote control. 66 | struct SimpleRemoteControl<'a> { 67 | command: Box, 68 | } 69 | impl<'a> SimpleRemoteControl<'a> { 70 | fn new() -> SimpleRemoteControl<'a> { 71 | SimpleRemoteControl { command: Box::new(NullCommand::new()) } 72 | } 73 | fn set_command(&mut self, cmd: Box) { 74 | self.command = cmd; 75 | } 76 | fn button_was_pressed(&self) { 77 | self.command.execute(); 78 | } 79 | } 80 | 81 | fn main() { 82 | let mut remote = SimpleRemoteControl::new(); 83 | let light = Light::new(); 84 | let light_on = LightOnCommand::new(light); 85 | let light_off = LightOffCommand::new(light); 86 | 87 | remote.button_was_pressed(); 88 | remote.set_command(Box::new(light_on)); 89 | remote.button_was_pressed(); 90 | remote.set_command(Box::new(light_off)); 91 | remote.button_was_pressed(); 92 | } -------------------------------------------------------------------------------- /strategy/src/simple2.rs: -------------------------------------------------------------------------------- 1 | type BinaryFn = Fn(T, T) -> T; 2 | 3 | 4 | struct Context<'a, T: 'a> { 5 | strategy: &'a BinaryFn, 6 | } 7 | 8 | 9 | impl<'a, T> Context<'a, T> { 10 | fn new(f: &'a BinaryFn) -> Context<'a, T> 11 | { 12 | Context { 13 | strategy: f, 14 | } 15 | } 16 | 17 | fn execute(&self, x: T, y: T) -> T 18 | { 19 | (*self.strategy)(x, y) 20 | } 21 | 22 | fn set_strategy(&mut self, f: &'a BinaryFn) 23 | { 24 | self.strategy = f 25 | } 26 | } 27 | 28 | 29 | fn main() { 30 | let add = |x: usize, y: usize| x + y; 31 | let mul = |x: usize, y: usize| x * y; 32 | let div = |x: usize, y: usize| x / y; 33 | let and = |x: usize, y: usize| x & y; 34 | let mut c = Context::new(&add); 35 | 36 | println!("{:?}", c.execute(1, 2)); 37 | 38 | c.set_strategy(&mul); 39 | println!("{:?}", c.execute(1, 2)); 40 | 41 | c.set_strategy(&div); 42 | println!("{:?}", c.execute(2, 2)); 43 | 44 | c.set_strategy(&and); 45 | println!("{:?}", c.execute(2, 2)); 46 | } -------------------------------------------------------------------------------- /template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "template" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /template/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /template/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Abstract { 2 | fn format_header(&self) -> String; 3 | fn format_content(&self, String) -> String; 4 | fn format_footer(&self) -> String; 5 | fn build(&self, msg: String) -> String 6 | { 7 | self.format_header() + &self.format_content(msg) + &self.format_footer() 8 | } 9 | } 10 | 11 | 12 | struct HtmlFormatter; 13 | impl Abstract for HtmlFormatter { 14 | fn format_header(&self) -> String 15 | { 16 | "\n\n\t\n".to_string() 17 | } 18 | 19 | fn format_content(&self, content: String) -> String 20 | { 21 | "\t\t".to_string() + &content 22 | } 23 | 24 | 25 | fn format_footer(&self) -> String 26 | { 27 | "\n\t\n".to_string() 28 | } 29 | } 30 | 31 | struct MarkdownFormatter; 32 | impl Abstract for MarkdownFormatter { 33 | fn format_header(&self) -> String 34 | { 35 | "# TODO\n".to_string() 36 | } 37 | 38 | fn format_content(&self, content: String) -> String 39 | { 40 | content 41 | } 42 | 43 | 44 | fn format_footer(&self) -> String 45 | { 46 | "".to_string() 47 | } 48 | } 49 | 50 | 51 | fn main() 52 | { 53 | let f1 = HtmlFormatter; 54 | let f2 = MarkdownFormatter; 55 | 56 | println!("{}\n", f1.build("this is content.".to_string())); 57 | println!("{}", f2.build("this is content.".to_string())); 58 | } -------------------------------------------------------------------------------- /visitor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "visitor" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /visitor/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /visitor/src/simple.rs: -------------------------------------------------------------------------------- 1 | trait Visitor { 2 | fn visit(&self, &Acceptor); 3 | } 4 | 5 | 6 | trait Acceptor { 7 | fn accept(&self, &Visitor); 8 | fn get_value(&self) -> &String; 9 | } 10 | 11 | 12 | struct VisitorX; 13 | impl Visitor for VisitorX { 14 | fn visit(&self, a: &Acceptor) 15 | { 16 | println!("VisitorX - Acceptor {}", a.get_value()); 17 | } 18 | } 19 | 20 | struct AcceptorX(String); 21 | impl Acceptor for AcceptorX { 22 | fn accept(&self, v: &Visitor) 23 | { 24 | v.visit(self); 25 | } 26 | 27 | 28 | fn get_value(&self) -> &String 29 | { 30 | &self.0 31 | } 32 | } 33 | 34 | fn main() 35 | { 36 | let v = VisitorX; 37 | let a1 = AcceptorX("Number 1".to_string()); 38 | let a2 = AcceptorX("Number 2".to_string()); 39 | 40 | a1.accept(&v); 41 | a2.accept(&v); 42 | } --------------------------------------------------------------------------------