├── .gitignore ├── LICENSE ├── README.md ├── SUMMARY.md ├── behavioral ├── command.py ├── iterator.py ├── observer.py ├── state.py ├── strategy.py └── template.py ├── book.json ├── creational ├── absfactory.py ├── factory.py └── sigleton.py ├── desgin-patterns-cheet.mindnode ├── QuickLook │ └── Preview.jpg ├── contents.xml ├── style.mindnodestyle │ ├── contents.xml │ └── metadata.plist └── viewState.plist ├── desgin-patterns-cheet.png ├── docs ├── behavioral │ ├── command.md │ ├── iterator.md │ ├── observer.md │ ├── state.md │ ├── strategy.md │ └── templete.md ├── creational │ ├── abstract_factory.md │ ├── factory_method.md │ └── singleton.md └── structural │ ├── adapter.md │ ├── composite.md │ ├── facade.md │ └── proxy.md └── structural ├── adapter.py ├── composite.py ├── facade.py └── proxy.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,python,pycharm 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (http://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # Typescript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | 64 | 65 | ### PyCharm ### 66 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 67 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 68 | 69 | # User-specific stuff: 70 | .idea/**/workspace.xml 71 | .idea/**/tasks.xml 72 | 73 | # Sensitive or high-churn files: 74 | .idea/**/dataSources/ 75 | .idea/**/dataSources.ids 76 | .idea/**/dataSources.xml 77 | .idea/**/dataSources.local.xml 78 | .idea/**/sqlDataSources.xml 79 | .idea/**/dynamic.xml 80 | .idea/**/uiDesigner.xml 81 | 82 | # Gradle: 83 | .idea/**/gradle.xml 84 | .idea/**/libraries 85 | 86 | # Mongo Explorer plugin: 87 | .idea/**/mongoSettings.xml 88 | 89 | ## File-based project format: 90 | *.iws 91 | 92 | ## Plugin-specific files: 93 | 94 | # IntelliJ 95 | /out/ 96 | 97 | # mpeltonen/sbt-idea plugin 98 | .idea_modules/ 99 | 100 | # JIRA plugin 101 | atlassian-ide-plugin.xml 102 | 103 | # Crashlytics plugin (for Android Studio and IntelliJ) 104 | com_crashlytics_export_strings.xml 105 | crashlytics.properties 106 | crashlytics-build.properties 107 | fabric.properties 108 | 109 | ### PyCharm Patch ### 110 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 111 | 112 | # *.iml 113 | # modules.xml 114 | # .idea/misc.xml 115 | # *.ipr 116 | 117 | ### Python ### 118 | # Byte-compiled / optimized / DLL files 119 | __pycache__/ 120 | *.py[cod] 121 | *$py.class 122 | 123 | # C extensions 124 | *.so 125 | 126 | # Distribution / packaging 127 | .Python 128 | env/ 129 | build/ 130 | develop-eggs/ 131 | dist/ 132 | downloads/ 133 | eggs/ 134 | .eggs/ 135 | lib/ 136 | lib64/ 137 | parts/ 138 | sdist/ 139 | var/ 140 | wheels/ 141 | *.egg-info/ 142 | .installed.cfg 143 | *.egg 144 | 145 | # PyInstaller 146 | # Usually these files are written by a python script from a template 147 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 148 | *.manifest 149 | *.spec 150 | 151 | # Installer logs 152 | pip-log.txt 153 | pip-delete-this-directory.txt 154 | 155 | # Unit test / coverage reports 156 | htmlcov/ 157 | .tox/ 158 | .coverage 159 | .coverage.* 160 | .cache 161 | nosetests.xml 162 | coverage.xml 163 | *,cover 164 | .hypothesis/ 165 | 166 | # Translations 167 | *.mo 168 | *.pot 169 | 170 | # Django stuff: 171 | local_settings.py 172 | 173 | # Flask stuff: 174 | instance/ 175 | .webassets-cache 176 | 177 | # Scrapy stuff: 178 | .scrapy 179 | 180 | # Sphinx documentation 181 | docs/_build/ 182 | 183 | # PyBuilder 184 | target/ 185 | 186 | # Jupyter Notebook 187 | .ipynb_checkpoints 188 | 189 | # pyenv 190 | .python-version 191 | 192 | # celery beat schedule file 193 | celerybeat-schedule 194 | 195 | # dotenv 196 | 197 | # virtualenv 198 | .venv 199 | venv/ 200 | ENV/ 201 | 202 | # Spyder project settings 203 | .spyderproject 204 | 205 | # Rope project settings 206 | .ropeproject 207 | 208 | # End of https://www.gitignore.io/api/node,python,pycharm 209 | 210 | .vscode/ 211 | .DS_Store 212 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 何翔宇(Sean Ho) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python 设计模式 2 | 3 | ![desgin-patterns](./desgin-patterns-cheet.png) 4 | 5 | ## Reference Books 6 | - [Head First 设计模式](https://book.douban.com/subject/2243615/) 7 | - [精通 Python 设计模式](https://book.douban.com/subject/26829015/) 8 | - [JavaScript 设计模式与开发实践](https://book.douban.com/subject/26382780/) 9 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | 3 | * [Python 设计模式](README.md) 4 | * 创建型模式 Creational 5 | - [工厂方法(Factory Method)](docs/creational/factory_method.md) 6 | - [抽象工厂(Abstract Factory)](docs/creational/abstract_factory.md) 7 | - [单例模式(Singleton)](docs/creational/singleton.md) 8 | * 行为型模式 Behavioral 9 | - [观察者模式(Observer)](docs/behavioral/observer.md) 10 | - [策略模式(Strategy)](docs/behavioral/strategy.md) 11 | - [命令模式(Command)](docs/behavioral/command.md) 12 | - [模板方法模式(Template Method)](docs/behavioral/templete.md) 13 | - [迭代器模式(Itertor)](docs/behavioral/iterator.md) 14 | - [状态模式(State)](docs/behavioral/state.md) 15 | * 结构型模式 Structural 16 | - [适配器模式(Adapter)](docs/structural/adapter.md) 17 | - [外观模式(Facade)](docs/structural/facade.md) 18 | - [组合模式(Composite)](docs/structural/composite.md) 19 | - [代理模式(Proxy)](docs/structural/proxy.md) 20 | -------------------------------------------------------------------------------- /behavioral/command.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class Transaction(object): 6 | def __init__(self): 7 | self.commands = [] 8 | self.success = [] 9 | 10 | def add_command(self, command): 11 | self.commands.append(command) 12 | 13 | def execute(self): 14 | """ 调用者不需要知道执行什么,只知道有 execute 方法""" 15 | for command in self.commands: 16 | command.execute() 17 | self.success.append(command) 18 | 19 | def undo(self): 20 | for command in self.success[::-1]: 21 | command.undo() 22 | 23 | 24 | class CreateCommand(object): 25 | def __init__(self, filename): 26 | self.filename = filename 27 | 28 | def execute(self): 29 | print('create a {}'.format(self.filename)) 30 | 31 | def undo(self): 32 | print('delete this {}'.format(self.filename)) 33 | 34 | 35 | class WriteCommand(object): 36 | def __init__(self, filename, content): 37 | self.filename = filename 38 | self.content = content 39 | 40 | def execute(self): 41 | print('write [{}] to {}'.format(self.content, self.filename)) 42 | 43 | def undo(self): 44 | print('remove [{}] from {}'.format(self.content, self.filename)) 45 | 46 | 47 | class ChomdCommand(object): 48 | def __init__(self, filename, mode): 49 | self.filename = filename 50 | self.mode = mode 51 | 52 | def execute(self): 53 | print('change {} mode to {}'.format(self.filename, self.mode)) 54 | 55 | def undo(self): 56 | print('revocer {} mode to {}'.format(self.filename, '644')) 57 | 58 | 59 | class MoveCommand(object): 60 | """ 假设这个命令发生了错误 """ 61 | 62 | def __init__(self, filename, to_path): 63 | self.filename = filename 64 | self.to_path = to_path 65 | 66 | def execute(self): 67 | print('move {} to {}'.format(self.filename, self.to_path)) 68 | raise Exception('you have not permission') 69 | 70 | def undo(self): 71 | print('move {} to {}'.format(self.to_path, self.filename)) 72 | 73 | 74 | if __name__ == '__main__': 75 | create_command = CreateCommand('test.file') 76 | write_command = WriteCommand('test.file', 'my name is zhengxiaowai') 77 | chmod_command = ChomdCommand('test.file', '600') 78 | 79 | file_operation = Transaction() 80 | file_operation.add_command(create_command) 81 | file_operation.add_command(write_command) 82 | file_operation.add_command(chmod_command) 83 | 84 | # file_operation.execute() 85 | 86 | try: 87 | # 发生错误恢复原始状态 88 | move_command = MoveCommand('test.file', '/etc/') 89 | file_operation.add_command(move_command) 90 | file_operation.execute() 91 | except: 92 | print('\nraise a error, start to undo:\n') 93 | file_operation.undo() 94 | -------------------------------------------------------------------------------- /behavioral/iterator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class BreakfastMenu(object): 6 | def __init__(self): 7 | self.items = [] 8 | 9 | def add_item(self, name, price): 10 | self.items.append((name, price)) 11 | 12 | def __iter__(self): 13 | """ return a Iterable object """ 14 | return iter(self.items) 15 | 16 | 17 | class LaunchMenu(object): 18 | def __init__(self): 19 | self.items = set() 20 | 21 | def add_item(self, name, price): 22 | self.items.add((name, price)) 23 | 24 | def __iter__(self): 25 | """ return a Iterable object """ 26 | return iter(self.items) 27 | 28 | 29 | class DinnerMenu(object): 30 | def __init__(self): 31 | self.items = {} 32 | 33 | def add_item(self, name, price): 34 | self.items[name] = price 35 | 36 | def __iter__(self): 37 | """ return a Iterable object """ 38 | return iter(((name, price) for name, price in self.items.items())) 39 | 40 | 41 | if __name__ == '__main__': 42 | breakfast_menu = BreakfastMenu() 43 | breakfast_menu.add_item('milk', 5) 44 | breakfast_menu.add_item('bread', 6) 45 | breakfast_menu.add_item('coffee', 7) 46 | breakfast_menu.add_item('donuts', 3) 47 | 48 | print('\nBreakfastMenu:') 49 | for item in breakfast_menu: 50 | print(item) 51 | 52 | launch_menu = LaunchMenu() 53 | launch_menu.add_item('milk', 5) 54 | launch_menu.add_item('bread', 6) 55 | launch_menu.add_item('coffee', 7) 56 | launch_menu.add_item('donuts', 3) 57 | 58 | print('\nLaunchMenu:') 59 | for item in launch_menu: 60 | print(item) 61 | 62 | dinner_menu = DinnerMenu() 63 | dinner_menu.add_item('milk', 5) 64 | dinner_menu.add_item('bread', 6) 65 | dinner_menu.add_item('coffee', 7) 66 | dinner_menu.add_item('donuts', 3) 67 | 68 | print('\nDinnerMenu:') 69 | for item in dinner_menu: 70 | print(item) 71 | -------------------------------------------------------------------------------- /behavioral/observer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class AbstractDisplay(object): 6 | def update(self): 7 | raise NotImplementedError( 8 | 'update is a abstract method which must be implemente') 9 | 10 | def display(self): 11 | raise NotImplementedError( 12 | 'display is a abstract method which must be implemente') 13 | 14 | 15 | class AbstractObservable(object): 16 | def register(self): 17 | raise NotImplementedError( 18 | 'register is a abstract method which must be implemente') 19 | 20 | def remove(self): 21 | raise NotImplementedError( 22 | 'remove is a abstract method which must be implemente') 23 | 24 | 25 | class Subject(object): 26 | def __init__(self, subject): 27 | self.subject = subject 28 | self._observers = [] 29 | 30 | def register(self, ob): 31 | self._observers.append(ob) 32 | 33 | def remove(self, ob): 34 | self._observers.remove(ob) 35 | 36 | def notify(self, data=None): 37 | for ob in self._observers: 38 | ob.update(data) 39 | 40 | 41 | class WeatherData(AbstractObservable): 42 | def __init__(self, *namespaces): 43 | self._nss = {} 44 | self._clock = None 45 | self._temperature = None 46 | self._humidity = None 47 | self._oxygen = None 48 | 49 | for ns in namespaces: 50 | self._nss[ns] = Subject(ns) 51 | 52 | def register(self, ns, ob): 53 | if ns not in self._nss: 54 | raise Exception('this {} is invalid namespace'.format(ns)) 55 | self._nss[ns].register(ob) 56 | 57 | def remove(self, ns, ob): 58 | return self._nss[ns].remove(ob) 59 | 60 | def set_measurement(self, data): 61 | self._clock = data['clock'] 62 | self._temperature = data['temperature'] 63 | self._humidity = data['humidity'] 64 | self._oxygen = data['oxygen'] 65 | 66 | for k in self._nss.keys(): 67 | if k != 'all': 68 | data = self 69 | 70 | self._nss[k].notify(data) 71 | 72 | @property 73 | def clock(self): 74 | return self._clock 75 | 76 | @property 77 | def temperature(self): 78 | return self._temperature 79 | 80 | @property 81 | def humidity(self): 82 | return self._humidity 83 | 84 | @property 85 | def oxygen(self): 86 | return self._oxygen 87 | 88 | 89 | class OverviewDisplay(AbstractDisplay): 90 | def __init__(self): 91 | self._data = {} 92 | 93 | def update(self, data): 94 | self._data = data 95 | self.display() 96 | 97 | def display(self): 98 | print(u'总览显示面板:') 99 | for k, v in self._data.items(): 100 | print(k + ': ' + str(v)) 101 | 102 | 103 | class TemperatureDisplay(AbstractDisplay): 104 | def __init__(self): 105 | self._storage = [] 106 | 107 | def update(self, data): 108 | dt = data.clock 109 | temperature = data.temperature 110 | self._storage.append((dt, temperature)) 111 | self.display() 112 | 113 | def display(self): 114 | print(u'温度显示面板:') 115 | for storey in self._storage: 116 | print(storey[0] + ': ' + str(storey[1])) 117 | 118 | 119 | if __name__ == '__main__': 120 | import time 121 | wd = WeatherData('all', 'temperature', 'humidity', 'oxygen') 122 | od = OverviewDisplay() 123 | td = TemperatureDisplay() 124 | 125 | wd.register('all', od) 126 | wd.register('temperature', td) 127 | 128 | wd.set_measurement({ 129 | 'clock': time.strftime("%Y-%m-%d %X", time.localtime()), 130 | 'temperature': 20, 131 | 'humidity': 60, 132 | 'oxygen': 10 133 | }) 134 | 135 | time.sleep(1) 136 | print('\n') 137 | wd.set_measurement({ 138 | 'clock': time.strftime("%Y-%m-%d %X", time.localtime()), 139 | 'temperature': 21, 140 | 'humidity': 58, 141 | 'oxygen': 7 142 | }) 143 | -------------------------------------------------------------------------------- /behavioral/state.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class State(object): 6 | def __init__(self, process): 7 | self.process = process 8 | 9 | def execute(self): 10 | raise NotImplementedError('you must implemment this method') 11 | 12 | def handup(self): 13 | raise NotImplementedError('you must implemment this method') 14 | 15 | def killed(self): 16 | raise NotImplementedError('you must implemment this method') 17 | 18 | 19 | class ProcessError(Exception): 20 | pass 21 | 22 | 23 | class CreatedState(State): 24 | def execute(self): 25 | print('execute process, transform to running state') 26 | self.process.set_state(self.process.running_state) 27 | 28 | def handup(self): 29 | print('handup process, transform to waitting state') 30 | self.process.set_state(self.process.waitting_state) 31 | 32 | def killed(self): 33 | print('killed process, transform to waitting teminated') 34 | self.process.set_state(self.process.terminated_state) 35 | 36 | 37 | class WaittingState(State): 38 | def execute(self): 39 | print('execute process, transform to running state') 40 | self.process.set_state(self.process.running_state) 41 | 42 | def handup(self): 43 | print('handup process, transform to waitting state') 44 | self.process.set_state(self.process.waitting_state) 45 | 46 | def killed(self): 47 | print('killed process, transform to waitting teminated') 48 | self.process.set_state(self.process.terminated_state) 49 | 50 | 51 | class RunningState(State): 52 | def execute(self): 53 | raise ProcessError('running state have not execute method') 54 | 55 | def handup(self): 56 | raise ProcessError('running state have not handup method') 57 | 58 | def killed(self): 59 | print('killed process, transform to waitting teminated') 60 | self.process.set_state(self.process.terminated_state) 61 | 62 | 63 | class TerminateState(State): 64 | def execute(self): 65 | raise ProcessError('running state have not execute method') 66 | 67 | def handup(self): 68 | raise ProcessError('running state have not handup method') 69 | 70 | def killed(self): 71 | print('process was teminated') 72 | self.process.set_state(self.process.terminated_state) 73 | 74 | 75 | class Process(object): 76 | def __init__(self, name): 77 | self.created_state = CreatedState(self) 78 | self.waitting_state = WaittingState(self) 79 | self.running_state = RunningState(self) 80 | self.terminated_state = TerminateState(self) 81 | 82 | self.name = name 83 | self.state = self.created_state 84 | 85 | def __str__(self): 86 | return self.state.__class__.__name__ 87 | 88 | def set_state(self, state): 89 | self.state = state 90 | 91 | def execute(self): 92 | self.state.execute() 93 | 94 | def handup(self): 95 | self.state.handup() 96 | 97 | def killed(self): 98 | self.state.killed() 99 | 100 | 101 | if __name__ == '__main__': 102 | print('Process NO.1') 103 | p1 = Process('p1') 104 | p1.execute() 105 | p1.killed() 106 | 107 | print('\nProcess NO.2') 108 | p2 = Process('p2') 109 | p2.handup() 110 | p2.execute() 111 | p2.killed() 112 | 113 | print('\nProcess NO.3') 114 | p3 = Process('p3') 115 | p3.handup() 116 | p3.handup() 117 | p3.killed() 118 | 119 | print('\nProcess NO.4') 120 | p4 = Process('p4') 121 | p4.killed() 122 | -------------------------------------------------------------------------------- /behavioral/strategy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 定义一系列计算年终奖的算法 5 | bouns_strategy = { 6 | 'S': lambda s: s * 4, 7 | 'A': lambda s: s * 3, 8 | 'B': lambda s: s * 2, 9 | 10 | # 添加 S+ 和 C 算法 11 | 'SP': lambda s: s * 5, 12 | 'C': lambda s: s, 13 | } 14 | 15 | 16 | def calculate_bouns(name, strategy, salary): 17 | return '{name} get {salary}'.format(name=name, salary=strategy(salary)) 18 | 19 | 20 | if __name__ == '__main__': 21 | print(calculate_bouns('jack', bouns_strategy['S'], 10000)) 22 | print(calculate_bouns('linda', bouns_strategy['A'], 10000)) 23 | print(calculate_bouns('sean', bouns_strategy['B'], 10000)) 24 | 25 | # 现在需求变化了,添加 S+ 作为最高级,C 级 作为最低级 26 | # jack 从 S 调整到 S+ 27 | # sean 从 B 调整到 C 28 | print('需求改变以后......') 29 | 30 | print(calculate_bouns('jack', bouns_strategy['SP'], 10000)) 31 | print(calculate_bouns('linda', bouns_strategy['A'], 10000)) 32 | print(calculate_bouns('sean', bouns_strategy['C'], 10000)) 33 | -------------------------------------------------------------------------------- /behavioral/template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from abc import ABCMeta, abstractmethod 5 | 6 | 7 | class CaffeineBeverage(metaclass=ABCMeta): 8 | def make_beverage(self): 9 | self.boil_water() 10 | self.brew() 11 | self.pour_in_cup() 12 | if (self.customer_want_condiments()): 13 | self.add_condiments() 14 | 15 | def boil_water(self): 16 | print('把水烧开') 17 | 18 | def pour_in_cup(self): 19 | print('倒入杯子中') 20 | 21 | def customer_want_condiments(self): 22 | # hook 23 | return False 24 | 25 | @abstractmethod 26 | def brew(self): 27 | pass 28 | 29 | @abstractmethod 30 | def add_condiments(self): 31 | pass 32 | 33 | 34 | class Tea(CaffeineBeverage): 35 | def brew(self): 36 | print('用沸水浸泡茶叶') 37 | 38 | def customer_want_condiments(self): 39 | return True 40 | 41 | def add_condiments(self): 42 | print('添加柠檬') 43 | 44 | 45 | class Coffee(CaffeineBeverage): 46 | def brew(self): 47 | print('用沸水冲泡咖啡') 48 | 49 | def customer_want_condiments(self): 50 | return False 51 | 52 | def add_condiments(self): 53 | print('添加牛奶和糖') 54 | 55 | 56 | if __name__ == '__main__': 57 | print('制作咖啡:') 58 | coffee = Coffee() 59 | coffee.make_beverage() 60 | print('\n制作茶:') 61 | tea = Tea() 62 | tea.make_beverage() 63 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "-search", 4 | "-lunr", 5 | "github", 6 | "comment", 7 | "fontsettings", 8 | "edit-link" 9 | ], 10 | "pluginsConfig": { 11 | "github": { 12 | "url": "https://github.com/zhengxiaowai/py-patterns" 13 | }, 14 | "edit-link": { 15 | "base": "https://github.com/zhengxiaowai/py-patterns/edit/master/", 16 | "label": "" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /creational/absfactory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from abc import ABC, abstractmethod 5 | 6 | 7 | class PizzaIngredientFactory(ABC): 8 | @abstractmethod 9 | def create_dougth(self): 10 | pass 11 | 12 | @abstractmethod 13 | def create_sauce(self): 14 | pass 15 | 16 | @abstractmethod 17 | def create_cheese(self): 18 | pass 19 | 20 | @abstractmethod 21 | def create_vegies(self): 22 | pass 23 | 24 | @abstractmethod 25 | def create_pepperoni(self): 26 | pass 27 | 28 | @abstractmethod 29 | def create_clam(self): 30 | pass 31 | 32 | 33 | class NYPizzaIngredientFactory(PizzaIngredientFactory): 34 | def __init__(self): 35 | self._location = type(self).__name__ 36 | 37 | def create_dougth(self): 38 | return self._location + ' dougth' 39 | 40 | def create_sauce(self): 41 | return self._location + ' sauce' 42 | 43 | def create_cheese(self): 44 | return self._location + ' cheese' 45 | 46 | def create_vegies(self): 47 | return self._location + ' vegies' 48 | 49 | def create_pepperoni(self): 50 | return self._location + ' pepperoni' 51 | 52 | def create_clam(self): 53 | return self._location + ' clam' 54 | 55 | 56 | class ChicagoPizzaIngredientFactory(PizzaIngredientFactory): 57 | def __init__(self): 58 | self._location = type(self).__name__ 59 | 60 | def create_dougth(self): 61 | return self._location + ' dougth' 62 | 63 | def create_sauce(self): 64 | return self._location + ' sauce' 65 | 66 | def create_cheese(self): 67 | return self._location + ' cheese' 68 | 69 | def create_vegies(self): 70 | return self._location + ' vegies' 71 | 72 | def create_pepperoni(self): 73 | return self._location + ' pepperoni' 74 | 75 | def create_clam(self): 76 | return self._location + ' clam' 77 | 78 | 79 | class Pizza(ABC): 80 | def __init__(self): 81 | self._dougth = '' 82 | self._sauce = '' 83 | self._cheese = '' 84 | self._vegies = '' 85 | self._pepperoni = '' 86 | self._clam = '' 87 | 88 | @abstractmethod 89 | def prepare(self): 90 | pass 91 | 92 | def bake(self): 93 | print('烘焙...') 94 | 95 | def cut(self): 96 | print('切片...') 97 | 98 | def box(self): 99 | print('装盒...') 100 | 101 | 102 | class CheesePizza(Pizza): 103 | def __init__(self, factory): 104 | super(CheesePizza, self).__init__() 105 | self._factory = factory 106 | 107 | def prepare(self): 108 | print('准备 CheesePizza 中...') 109 | self._dougth = self._factory.create_dougth() 110 | self._sauce = self._factory.create_sauce() 111 | self._cheese = self._factory.create_cheese() 112 | 113 | def __str__(self): 114 | return 'CheesePizza 有: {}, {}, {}'.format( 115 | self._dougth, self._sauce, self._cheese) 116 | 117 | 118 | class ClamPizza(Pizza): 119 | 120 | def __init__(self, factory): 121 | super(ClamPizza, self).__init__() 122 | self._factory = factory 123 | 124 | def prepare(self): 125 | print('准备 ClamPizza 中...') 126 | self._dougth = self._factory.create_dougth() 127 | self._sauce = self._factory.create_sauce() 128 | self._cheese = self._factory.create_cheese() 129 | self._clam = self._factory.create_clam() 130 | 131 | def __str__(self): 132 | return 'CheesePizza 有: {}, {}, {}, {}'.format( 133 | self._dougth, self._sauce, self._cheese, self._clam) 134 | 135 | 136 | class PizzaStore(ABC): 137 | def order_pizza(self, pizza_type): 138 | pizza = self.create_pizza(pizza_type) 139 | 140 | pizza.prepare() 141 | pizza.bake() 142 | pizza.cut() 143 | pizza.box() 144 | 145 | return pizza 146 | 147 | @abstractmethod 148 | def create_pizza(self): 149 | pass 150 | 151 | 152 | class NYPizzaStore(PizzaStore): 153 | def create_pizza(self, item): 154 | ny_pizza_ingredient_factory = NYPizzaIngredientFactory() 155 | if item == 'cheese': 156 | return CheesePizza(ny_pizza_ingredient_factory) 157 | elif item == 'clam': 158 | return ClamPizza(ny_pizza_ingredient_factory) 159 | 160 | 161 | class ChicagoPizzaStore(PizzaStore): 162 | def create_pizza(self, item): 163 | chicago_pizza_ingredient_factory = ChicagoPizzaIngredientFactory() 164 | if item == 'cheese': 165 | return CheesePizza(chicago_pizza_ingredient_factory) 166 | elif item == 'clam': 167 | return ClamPizza(chicago_pizza_ingredient_factory) 168 | 169 | 170 | if __name__ == '__main__': 171 | # 纽约披萨店 172 | ny_pizza_store = NYPizzaStore() 173 | ny_pizza1 = ny_pizza_store.order_pizza('cheese') 174 | print(ny_pizza1) 175 | 176 | ny_pizza2 = ny_pizza_store.order_pizza('clam') 177 | print(ny_pizza1) 178 | 179 | # 芝加哥披萨店 180 | chicago_pizza_store = ChicagoPizzaStore() 181 | chicago_pizza1 = chicago_pizza_store.order_pizza('cheese') 182 | print(chicago_pizza1) 183 | 184 | chicago_pizza2 = chicago_pizza_store.order_pizza('clam') 185 | print(chicago_pizza1) 186 | -------------------------------------------------------------------------------- /creational/factory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import unicode_literals, print_function 5 | 6 | 7 | class Pizza(object): 8 | """ Pizza 抽象类 """ 9 | 10 | def __init__(self): 11 | self.name = self.getPizzaName() 12 | 13 | def prepare(self): 14 | print('准备...') 15 | 16 | def bake(self): 17 | print('烘焙...') 18 | 19 | def cut(self): 20 | print('切片...') 21 | 22 | def box(self): 23 | print('装盒...') 24 | 25 | 26 | class NYStyleCheesePizza(Pizza): 27 | """ Pizza 子类 """ 28 | 29 | def getPizzaName(self): 30 | return '纽约风味 cheese 披萨' 31 | 32 | 33 | class ChicagoCheesePizza(Pizza): 34 | """ Pizza 子类 """ 35 | 36 | def getPizzaName(self): 37 | return '芝加哥风味 cheese 披萨' 38 | 39 | def cut(self): 40 | """ 覆盖父类方法 """ 41 | print('方块切片...') 42 | 43 | 44 | class PizzaStore(object): 45 | def order_pizza(self, pizza_type): 46 | pizza = self.create_pizza(pizza_type) 47 | 48 | pizza.prepare() 49 | pizza.bake() 50 | pizza.cut() 51 | pizza.box() 52 | 53 | return pizza 54 | 55 | 56 | class NYPizzaStore(PizzaStore): 57 | def create_pizza(self, item): 58 | if item == 'cheese': 59 | return NYStyleCheesePizza() 60 | elif item == 'veggie': 61 | # 同上 62 | pass 63 | 64 | 65 | class ChicagoPizzaStore(PizzaStore): 66 | def create_pizza(self, item): 67 | if item == 'cheese': 68 | return ChicagoCheesePizza() 69 | elif item == 'veggie': 70 | # 同上 71 | pass 72 | 73 | 74 | if __name__ == '__main__': 75 | ny_pizza_store = NYPizzaStore() 76 | ny_cheese_pizza = ny_pizza_store.order_pizza('cheese') 77 | print('获得 {}'.format(ny_cheese_pizza.name)) 78 | 79 | print('\n') 80 | 81 | chicago_pizza_store = ChicagoPizzaStore() 82 | chicago_cheese_pizza = chicago_pizza_store.order_pizza('cheese') 83 | print('获得 {}'.format(chicago_cheese_pizza.name)) 84 | -------------------------------------------------------------------------------- /creational/sigleton.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | class Singleton(type): 5 | _instances = {} 6 | def __call__(cls, *args, **kwargs): 7 | if cls not in cls._instances: 8 | cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 9 | return cls._instances[cls] 10 | 11 | class MyClass(object): 12 | __metaclass__ = Singleton -------------------------------------------------------------------------------- /desgin-patterns-cheet.mindnode/QuickLook/Preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengxiaowai/py-patterns/867ef54c34994752afd77fd0ac54b99567ccfa52/desgin-patterns-cheet.mindnode/QuickLook/Preview.jpg -------------------------------------------------------------------------------- /desgin-patterns-cheet.mindnode/contents.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | author 6 | 7 | comments 8 | 9 | isUsingConstrainedLayout 10 | 11 | keywords 12 | 13 | mindMap 14 | 15 | associations 16 | 17 | color 18 | {0.956, 0.966, 0.956, 1.000} 19 | mainNodes 20 | 21 | 22 | contentAlignment 23 | 1 24 | fillColor 25 | {1.000, 1.000, 1.000, 1.000} 26 | isDecreasingBranchThickness 27 | 28 | isDrawingFill 29 | 30 | isLeftAligned 31 | 32 | location 33 | {-0.796875, -0.84765625} 34 | nodeID 35 | 60D941FC-CEB3-487F-8734-7B885421674C 36 | strokeColor 37 | {0.965, 0.965, 0.965, 1.000} 38 | strokeStyle 39 | 0 40 | strokeWidth 41 | 2 42 | subnodes 43 | 44 | 45 | contentAlignment 46 | 1 47 | fillColor 48 | {1.000, 1.000, 1.000, 1.000} 49 | isDecreasingBranchThickness 50 | 51 | isDrawingFill 52 | 53 | isLeftAligned 54 | 55 | location 56 | {173.203125, -312.84765625} 57 | nodeID 58 | 6A93D65D-5CF3-4FAC-B603-FEC928E30DE2 59 | strokeColor 60 | {0.136, 0.807, 0.880, 1.000} 61 | strokeStyle 62 | 0 63 | strokeWidth 64 | 6 65 | subnodes 66 | 67 | 68 | contentAlignment 69 | 1 70 | fillColor 71 | {1.000, 1.000, 1.000, 1.000} 72 | isDecreasingBranchThickness 73 | 74 | isDrawingFill 75 | 76 | isLeftAligned 77 | 78 | location 79 | {322.203125, -394.84765625} 80 | nodeID 81 | 41E974E3-E8F9-4E0C-816E-410143C14D07 82 | strokeColor 83 | {0.136, 0.807, 0.880, 1.000} 84 | strokeStyle 85 | 0 86 | strokeWidth 87 | 5 88 | subnodes 89 | 90 | title 91 | 92 | constrainedWidth 93 | 300 94 | htmlText 95 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>单一职责原则(SRP)</p> 96 | shrinkToFitContent 97 | 1 98 | text 99 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 100 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 101 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 102 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 103 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 104 | 105 | \f0\fs36 \cf2 \'b5\'a5\'d2\'bb\'d6\'b0\'d4\'f0\'d4\'ad\'d4\'f2\'a3\'a8SRP\'a3\'a9} 106 | 107 | 108 | 109 | contentAlignment 110 | 1 111 | fillColor 112 | {1.000, 1.000, 1.000, 1.000} 113 | isDecreasingBranchThickness 114 | 115 | isDrawingFill 116 | 117 | isLeftAligned 118 | 119 | location 120 | {322.203125, -353.84765625} 121 | nodeID 122 | 9F46EBA5-2475-4846-9489-87FC8778E771 123 | strokeColor 124 | {0.136, 0.807, 0.880, 1.000} 125 | strokeStyle 126 | 0 127 | strokeWidth 128 | 5 129 | subnodes 130 | 131 | title 132 | 133 | constrainedWidth 134 | 300 135 | htmlText 136 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>开放封闭原则(OCP)</p> 137 | shrinkToFitContent 138 | 1 139 | text 140 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 141 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 142 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 143 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 144 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 145 | 146 | \f0\fs36 \cf2 \'bf\'aa\'b7\'c5\'b7\'e2\'b1\'d5\'d4\'ad\'d4\'f2\'a3\'a8OCP\'a3\'a9} 147 | 148 | 149 | 150 | contentAlignment 151 | 1 152 | fillColor 153 | {1.000, 1.000, 1.000, 1.000} 154 | isDecreasingBranchThickness 155 | 156 | isDrawingFill 157 | 158 | isLeftAligned 159 | 160 | location 161 | {322.203125, -312.84765625} 162 | nodeID 163 | 88EE68B2-67E3-4584-A1AA-E062A037ED81 164 | strokeColor 165 | {0.136, 0.807, 0.880, 1.000} 166 | strokeStyle 167 | 0 168 | strokeWidth 169 | 5 170 | subnodes 171 | 172 | title 173 | 174 | constrainedWidth 175 | 300 176 | htmlText 177 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>里氏替换原则(LSP)</p> 178 | shrinkToFitContent 179 | 1 180 | text 181 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 182 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 183 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 184 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 185 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 186 | 187 | \f0\fs36 \cf2 \'c0\'ef\'ca\'cf\'cc\'e6\'bb\'bb\'d4\'ad\'d4\'f2\'a3\'a8LSP\'a3\'a9} 188 | 189 | 190 | 191 | contentAlignment 192 | 1 193 | fillColor 194 | {1.000, 1.000, 1.000, 1.000} 195 | isDecreasingBranchThickness 196 | 197 | isDrawingFill 198 | 199 | isLeftAligned 200 | 201 | location 202 | {322.203125, -271.84765625} 203 | nodeID 204 | 63856386-D6E8-43DE-828D-37BCC18027FC 205 | strokeColor 206 | {0.136, 0.807, 0.880, 1.000} 207 | strokeStyle 208 | 0 209 | strokeWidth 210 | 5 211 | subnodes 212 | 213 | title 214 | 215 | constrainedWidth 216 | 300 217 | htmlText 218 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>接口分离原则(ISP)</p> 219 | shrinkToFitContent 220 | 1 221 | text 222 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 223 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 224 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 225 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 226 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 227 | 228 | \f0\fs36 \cf2 \'bd\'d3\'bf\'da\'b7\'d6\'c0\'eb\'d4\'ad\'d4\'f2\'a3\'a8ISP\'a3\'a9} 229 | 230 | 231 | 232 | contentAlignment 233 | 1 234 | fillColor 235 | {1.000, 1.000, 1.000, 1.000} 236 | isDecreasingBranchThickness 237 | 238 | isDrawingFill 239 | 240 | isLeftAligned 241 | 242 | location 243 | {322.203125, -230.84765625} 244 | nodeID 245 | 72D336DB-E6FF-4217-ABC1-6EB804545688 246 | strokeColor 247 | {0.136, 0.807, 0.880, 1.000} 248 | strokeStyle 249 | 0 250 | strokeWidth 251 | 5 252 | subnodes 253 | 254 | title 255 | 256 | constrainedWidth 257 | 300 258 | htmlText 259 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>依赖倒置原则(DIP)</p> 260 | shrinkToFitContent 261 | 1 262 | text 263 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 264 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 265 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 266 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 267 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 268 | 269 | \f0\fs36 \cf2 \'d2\'c0\'c0\'b5\'b5\'b9\'d6\'c3\'d4\'ad\'d4\'f2\'a3\'a8DIP\'a3\'a9} 270 | 271 | 272 | 273 | title 274 | 275 | constrainedWidth 276 | 300 277 | htmlText 278 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>S.O.L.I.D.</p> 279 | shrinkToFitContent 280 | 1 281 | text 282 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 283 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 284 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 285 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 286 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 287 | 288 | \f0\fs36 \cf2 S.O.L.I.D.} 289 | 290 | 291 | 292 | contentAlignment 293 | 1 294 | fillColor 295 | {1.000, 1.000, 1.000, 1.000} 296 | isDecreasingBranchThickness 297 | 298 | isDrawingFill 299 | 300 | isLeftAligned 301 | 302 | location 303 | {-163.796875, -159.34765625} 304 | nodeID 305 | 0A017954-7EB9-4B3F-8EE2-3782B600CF3F 306 | strokeColor 307 | {0.689, 0.215, 0.952, 1.000} 308 | strokeStyle 309 | 0 310 | strokeWidth 311 | 6 312 | subnodes 313 | 314 | 315 | contentAlignment 316 | 1 317 | fillColor 318 | {1.000, 1.000, 1.000, 1.000} 319 | isDecreasingBranchThickness 320 | 321 | isDrawingFill 322 | 323 | isLeftAligned 324 | 325 | location 326 | {-308.796875, -237.84765625} 327 | nodeID 328 | C5D9DC14-33DB-4EC7-BD85-5E47B9CFD410 329 | strokeColor 330 | {0.689, 0.215, 0.952, 1.000} 331 | strokeStyle 332 | 0 333 | strokeWidth 334 | 5 335 | subnodes 336 | 337 | 338 | contentAlignment 339 | 1 340 | fillColor 341 | {1.000, 1.000, 1.000, 1.000} 342 | isDecreasingBranchThickness 343 | 344 | isDrawingFill 345 | 346 | isLeftAligned 347 | 348 | location 349 | {-669.796875, -262.84765625} 350 | nodeID 351 | AAEA95FF-9D24-41B9-BC30-CEAB585DA661 352 | strokeColor 353 | {0.689, 0.215, 0.952, 1.000} 354 | strokeStyle 355 | 0 356 | strokeWidth 357 | 4 358 | subnodes 359 | 360 | title 361 | 362 | constrainedWidth 363 | 300 364 | htmlText 365 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类实例化延迟到其子类。</p> 366 | shrinkToFitContent 367 | 1 368 | text 369 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 370 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 371 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 372 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 373 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 374 | 375 | \f0\fs36 \cf2 \'b6\'a8\'d2\'e5\'d2\'bb\'b8\'f6\'d3\'c3\'d3\'da\'b4\'b4\'bd\'a8\'b6\'d4\'cf\'f3\'b5\'c4\'bd\'d3\'bf\'da\'a3\'ac\'c8\'c3\'d7\'d3\'c0\'e0\'be\'f6\'b6\'a8\'ca\'b5\'c0\'fd\'bb\'af\'c4\'c4\'d2\'bb\'b8\'f6\'c0\'e0\'a1\'a3\'b9\'a4\'b3\'a7\'b7\'bd\'b7\'a8\'ca\'b9\'d2\'bb\'b8\'f6\'c0\'e0\'ca\'b5\'c0\'fd\'bb\'af\'d1\'d3\'b3\'d9\'b5\'bd\'c6\'e4\'d7\'d3\'c0\'e0\'a1\'a3} 376 | 377 | 378 | 379 | title 380 | 381 | constrainedWidth 382 | 300 383 | htmlText 384 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>工厂方法</p> 385 | shrinkToFitContent 386 | 1 387 | text 388 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 389 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 390 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 391 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 392 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 393 | 394 | \f0\fs36 \cf2 \'b9\'a4\'b3\'a7\'b7\'bd\'b7\'a8} 395 | 396 | 397 | 398 | contentAlignment 399 | 1 400 | fillColor 401 | {1.000, 1.000, 1.000, 1.000} 402 | isDecreasingBranchThickness 403 | 404 | isDrawingFill 405 | 406 | isLeftAligned 407 | 408 | location 409 | {-308.796875, -146.84765625} 410 | nodeID 411 | 07F9E0E9-43EC-4F68-B4BF-497A851394AA 412 | strokeColor 413 | {0.689, 0.215, 0.952, 1.000} 414 | strokeStyle 415 | 0 416 | strokeWidth 417 | 5 418 | subnodes 419 | 420 | 421 | contentAlignment 422 | 1 423 | fillColor 424 | {1.000, 1.000, 1.000, 1.000} 425 | isDecreasingBranchThickness 426 | 427 | isDrawingFill 428 | 429 | isLeftAligned 430 | 431 | location 432 | {-669.796875, -171.84765625} 433 | nodeID 434 | 43054F31-A1F8-45C7-A3F8-007B7D86D8B7 435 | strokeColor 436 | {0.689, 0.215, 0.952, 1.000} 437 | strokeStyle 438 | 0 439 | strokeWidth 440 | 4 441 | subnodes 442 | 443 | title 444 | 445 | constrainedWidth 446 | 300 447 | htmlText 448 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。</p> 449 | shrinkToFitContent 450 | 1 451 | text 452 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 453 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 454 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 455 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 456 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 457 | 458 | \f0\fs36 \cf2 \'cc\'e1\'b9\'a9\'d2\'bb\'b8\'f6\'b4\'b4\'bd\'a8\'d2\'bb\'cf\'b5\'c1\'d0\'cf\'e0\'b9\'d8\'bb\'f2\'cf\'e0\'bb\'a5\'d2\'c0\'c0\'b5\'b6\'d4\'cf\'f3\'b5\'c4\'bd\'d3\'bf\'da\'a3\'ac\'b6\'f8\'ce\'de\'d0\'e8\'d6\'b8\'b6\'a8\'cb\'fc\'c3\'c7\'be\'df\'cc\'e5\'b5\'c4\'c0\'e0\'a1\'a3} 459 | 460 | 461 | 462 | title 463 | 464 | constrainedWidth 465 | 300 466 | htmlText 467 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>抽象工厂</p> 468 | shrinkToFitContent 469 | 1 470 | text 471 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 472 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 473 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 474 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 475 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 476 | 477 | \f0\fs36 \cf2 \'b3\'e9\'cf\'f3\'b9\'a4\'b3\'a7} 478 | 479 | 480 | 481 | contentAlignment 482 | 1 483 | fillColor 484 | {1.000, 1.000, 1.000, 1.000} 485 | isDecreasingBranchThickness 486 | 487 | isDrawingFill 488 | 489 | isLeftAligned 490 | 491 | location 492 | {-308.796875, -68.34765625} 493 | nodeID 494 | 1C4CF886-8F82-4DBA-97A6-FB1B8C3EEF54 495 | strokeColor 496 | {0.689, 0.215, 0.952, 1.000} 497 | strokeStyle 498 | 0 499 | strokeWidth 500 | 5 501 | subnodes 502 | 503 | 504 | contentAlignment 505 | 1 506 | fillColor 507 | {1.000, 1.000, 1.000, 1.000} 508 | isDecreasingBranchThickness 509 | 510 | isDrawingFill 511 | 512 | isLeftAligned 513 | 514 | location 515 | {-669.796875, -80.84765625} 516 | nodeID 517 | 947EDB99-4ACF-46FF-B5FF-75AF34F94606 518 | strokeColor 519 | {0.689, 0.215, 0.952, 1.000} 520 | strokeStyle 521 | 0 522 | strokeWidth 523 | 4 524 | subnodes 525 | 526 | title 527 | 528 | constrainedWidth 529 | 300 530 | htmlText 531 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>保证一个类仅有一个实例,并提供一个访问它的全局访问点。</p> 532 | shrinkToFitContent 533 | 1 534 | text 535 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 536 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 537 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 538 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 539 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 540 | 541 | \f0\fs36 \cf2 \'b1\'a3\'d6\'a4\'d2\'bb\'b8\'f6\'c0\'e0\'bd\'f6\'d3\'d0\'d2\'bb\'b8\'f6\'ca\'b5\'c0\'fd\'a3\'ac\'b2\'a2\'cc\'e1\'b9\'a9\'d2\'bb\'b8\'f6\'b7\'c3\'ce\'ca\'cb\'fc\'b5\'c4\'c8\'ab\'be\'d6\'b7\'c3\'ce\'ca\'b5\'e3\'a1\'a3} 542 | 543 | 544 | 545 | title 546 | 547 | constrainedWidth 548 | 300 549 | htmlText 550 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>单例模式</p> 551 | shrinkToFitContent 552 | 1 553 | text 554 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 555 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 556 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 557 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 558 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 559 | 560 | \f0\fs36 \cf2 \'b5\'a5\'c0\'fd\'c4\'a3\'ca\'bd} 561 | 562 | 563 | 564 | title 565 | 566 | constrainedWidth 567 | 300 568 | htmlText 569 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>创建型模式</p> 570 | shrinkToFitContent 571 | 1 572 | text 573 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 574 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 575 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 576 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 577 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 578 | 579 | \f0\fs36 \cf2 \'b4\'b4\'bd\'a8\'d0\'cd\'c4\'a3\'ca\'bd} 580 | 581 | 582 | 583 | contentAlignment 584 | 1 585 | fillColor 586 | {1.000, 1.000, 1.000, 1.000} 587 | isDecreasingBranchThickness 588 | 589 | isDrawingFill 590 | 591 | isLeftAligned 592 | 593 | location 594 | {173.203125, 112.65234375} 595 | nodeID 596 | 8F68EBBF-5FE0-4A0F-806B-85A0786B0BC6 597 | strokeColor 598 | {0.144, 0.670, 1.000, 1.000} 599 | strokeStyle 600 | 0 601 | strokeWidth 602 | 6 603 | subnodes 604 | 605 | 606 | contentAlignment 607 | 1 608 | fillColor 609 | {1.000, 1.000, 1.000, 1.000} 610 | isDecreasingBranchThickness 611 | 612 | isDrawingFill 613 | 614 | isLeftAligned 615 | 616 | location 617 | {336.203125, -152.34765625} 618 | nodeID 619 | 1F47A99E-5F5D-4577-8009-F516F6654D20 620 | strokeColor 621 | {0.144, 0.670, 1.000, 1.000} 622 | strokeStyle 623 | 0 624 | strokeWidth 625 | 5 626 | subnodes 627 | 628 | 629 | contentAlignment 630 | 1 631 | fillColor 632 | {1.000, 1.000, 1.000, 1.000} 633 | isDecreasingBranchThickness 634 | 635 | isDrawingFill 636 | 637 | isLeftAligned 638 | 639 | location 640 | {499.203125, -189.84765625} 641 | nodeID 642 | B3305091-4420-43BC-9E1D-FC3D2C3EEAF3 643 | strokeColor 644 | {0.144, 0.670, 1.000, 1.000} 645 | strokeStyle 646 | 0 647 | strokeWidth 648 | 4 649 | subnodes 650 | 651 | title 652 | 653 | constrainedWidth 654 | 300 655 | htmlText 656 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>定义对象间的一种一对多的依赖关系 ,当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并被自动更新。</p> 657 | shrinkToFitContent 658 | 1 659 | text 660 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 661 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 662 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 663 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 664 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 665 | 666 | \f0\fs36 \cf2 \'b6\'a8\'d2\'e5\'b6\'d4\'cf\'f3\'bc\'e4\'b5\'c4\'d2\'bb\'d6\'d6\'d2\'bb\'b6\'d4\'b6\'e0\'b5\'c4\'d2\'c0\'c0\'b5\'b9\'d8\'cf\'b5 ,\'b5\'b1\'d2\'bb\'b8\'f6\'b6\'d4\'cf\'f3\'b5\'c4\'d7\'b4\'cc\'ac\'b7\'a2\'c9\'fa\'b8\'c4\'b1\'e4\'ca\'b1 , \'cb\'f9\'d3\'d0\'d2\'c0\'c0\'b5\'d3\'da\'cb\'fc\'b5\'c4\'b6\'d4\'cf\'f3\'b6\'bc\'b5\'c3\'b5\'bd\'cd\'a8\'d6\'aa\'b2\'a2\'b1\'bb\'d7\'d4\'b6\'af\'b8\'fc\'d0\'c2\'a1\'a3} 667 | 668 | 669 | 670 | title 671 | 672 | constrainedWidth 673 | 300 674 | htmlText 675 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>观察者模式</p> 676 | shrinkToFitContent 677 | 1 678 | text 679 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 680 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 681 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 682 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 683 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 684 | 685 | \f0\fs36 \cf2 \'b9\'db\'b2\'ec\'d5\'df\'c4\'a3\'ca\'bd} 686 | 687 | 688 | 689 | contentAlignment 690 | 1 691 | fillColor 692 | {1.000, 1.000, 1.000, 1.000} 693 | isDecreasingBranchThickness 694 | 695 | isDrawingFill 696 | 697 | isLeftAligned 698 | 699 | location 700 | {336.203125, -48.84765625} 701 | nodeID 702 | 9EF8A576-8B0A-4A21-BDBF-FCE0BE24D675 703 | strokeColor 704 | {0.144, 0.670, 1.000, 1.000} 705 | strokeStyle 706 | 0 707 | strokeWidth 708 | 5 709 | subnodes 710 | 711 | 712 | contentAlignment 713 | 1 714 | fillColor 715 | {1.000, 1.000, 1.000, 1.000} 716 | isDecreasingBranchThickness 717 | 718 | isDrawingFill 719 | 720 | isLeftAligned 721 | 722 | location 723 | {481.203125, -73.84765625} 724 | nodeID 725 | 0B96EA3D-45E4-4815-8841-FC1C371B499D 726 | strokeColor 727 | {0.144, 0.670, 1.000, 1.000} 728 | strokeStyle 729 | 0 730 | strokeWidth 731 | 4 732 | subnodes 733 | 734 | title 735 | 736 | constrainedWidth 737 | 300 738 | htmlText 739 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>定义一系列算法,把他们封装起来,并且可以相互替换使用,使得算法可以独立于客户端而变化。</p> 740 | shrinkToFitContent 741 | 1 742 | text 743 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 744 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 745 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 746 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 747 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 748 | 749 | \f0\fs36 \cf2 \'b6\'a8\'d2\'e5\'d2\'bb\'cf\'b5\'c1\'d0\'cb\'e3\'b7\'a8\'a3\'ac\'b0\'d1\'cb\'fb\'c3\'c7\'b7\'e2\'d7\'b0\'c6\'f0\'c0\'b4\'a3\'ac\'b2\'a2\'c7\'d2\'bf\'c9\'d2\'d4\'cf\'e0\'bb\'a5\'cc\'e6\'bb\'bb\'ca\'b9\'d3\'c3\'a3\'ac\'ca\'b9\'b5\'c3\'cb\'e3\'b7\'a8\'bf\'c9\'d2\'d4\'b6\'c0\'c1\'a2\'d3\'da\'bf\'cd\'bb\'a7\'b6\'cb\'b6\'f8\'b1\'e4\'bb\'af\'a1\'a3} 750 | 751 | 752 | 753 | title 754 | 755 | constrainedWidth 756 | 300 757 | htmlText 758 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>策略模式</p> 759 | shrinkToFitContent 760 | 1 761 | text 762 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 763 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 764 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 765 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 766 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 767 | 768 | \f0\fs36 \cf2 \'b2\'df\'c2\'d4\'c4\'a3\'ca\'bd} 769 | 770 | 771 | 772 | contentAlignment 773 | 1 774 | fillColor 775 | {1.000, 1.000, 1.000, 1.000} 776 | isDecreasingBranchThickness 777 | 778 | isDrawingFill 779 | 780 | isLeftAligned 781 | 782 | location 783 | {336.203125, 54.65234375} 784 | nodeID 785 | 0DFDA0DD-C3B5-4C44-A7CD-EDF139603136 786 | strokeColor 787 | {0.144, 0.670, 1.000, 1.000} 788 | strokeStyle 789 | 0 790 | strokeWidth 791 | 5 792 | subnodes 793 | 794 | 795 | contentAlignment 796 | 1 797 | fillColor 798 | {1.000, 1.000, 1.000, 1.000} 799 | isDecreasingBranchThickness 800 | 801 | isDrawingFill 802 | 803 | isLeftAligned 804 | 805 | location 806 | {481.203125, 17.15234375} 807 | nodeID 808 | 42E1E5EF-1792-49D1-A9B2-8F72CB416133 809 | strokeColor 810 | {0.144, 0.670, 1.000, 1.000} 811 | strokeStyle 812 | 0 813 | strokeWidth 814 | 4 815 | subnodes 816 | 817 | title 818 | 819 | constrainedWidth 820 | 300 821 | htmlText 822 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。</p> 823 | shrinkToFitContent 824 | 1 825 | text 826 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 827 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 828 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 829 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 830 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 831 | 832 | \f0\fs36 \cf2 \'bd\'ab\'d2\'bb\'b8\'f6\'c7\'eb\'c7\'f3\'b7\'e2\'d7\'b0\'ce\'aa\'d2\'bb\'b8\'f6\'b6\'d4\'cf\'f3\'a3\'ac\'b4\'d3\'b6\'f8\'ca\'b9\'c4\'e3\'bf\'c9\'d3\'c3\'b2\'bb\'cd\'ac\'b5\'c4\'c7\'eb\'c7\'f3\'b6\'d4\'bf\'cd\'bb\'a7\'bd\'f8\'d0\'d0\'b2\'ce\'ca\'fd\'bb\'af;\'b6\'d4\'c7\'eb\'c7\'f3\'c5\'c5\'b6\'d3\'bb\'f2\'bc\'c7\'c2\'bc\'c7\'eb\'c7\'f3\'c8\'d5\'d6\'be\'a3\'ac\'d2\'d4\'bc\'b0\'d6\'a7\'b3\'d6\'bf\'c9\'b3\'b7\'cf\'fb\'b5\'c4\'b2\'d9\'d7\'f7\'a1\'a3} 833 | 834 | 835 | 836 | title 837 | 838 | constrainedWidth 839 | 300 840 | htmlText 841 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>命令模式</p> 842 | shrinkToFitContent 843 | 1 844 | text 845 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 846 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 847 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 848 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 849 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 850 | 851 | \f0\fs36 \cf2 \'c3\'fc\'c1\'ee\'c4\'a3\'ca\'bd} 852 | 853 | 854 | 855 | contentAlignment 856 | 1 857 | fillColor 858 | {1.000, 1.000, 1.000, 1.000} 859 | isDecreasingBranchThickness 860 | 861 | isDrawingFill 862 | 863 | isLeftAligned 864 | 865 | location 866 | {336.203125, 183.15234375} 867 | nodeID 868 | AD3A6FB5-149D-42C4-89E8-9013B857F1D9 869 | strokeColor 870 | {0.144, 0.670, 1.000, 1.000} 871 | strokeStyle 872 | 0 873 | strokeWidth 874 | 5 875 | subnodes 876 | 877 | 878 | contentAlignment 879 | 1 880 | fillColor 881 | {1.000, 1.000, 1.000, 1.000} 882 | isDecreasingBranchThickness 883 | 884 | isDrawingFill 885 | 886 | isLeftAligned 887 | 888 | location 889 | {517.203125, 133.15234375} 890 | nodeID 891 | B5985F5A-D82F-484C-B78F-94AD51B17E97 892 | strokeColor 893 | {0.144, 0.670, 1.000, 1.000} 894 | strokeStyle 895 | 0 896 | strokeWidth 897 | 4 898 | subnodes 899 | 900 | title 901 | 902 | constrainedWidth 903 | 300 904 | htmlText 905 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。</p> 906 | shrinkToFitContent 907 | 1 908 | text 909 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 910 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 911 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 912 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 913 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 914 | 915 | \f0\fs36 \cf2 \'d4\'da\'d2\'bb\'b8\'f6\'b7\'bd\'b7\'a8\'d6\'d0\'b6\'a8\'d2\'e5\'d2\'bb\'b8\'f6\'cb\'e3\'b7\'a8\'b5\'c4\'b9\'c7\'bc\'dc\'a3\'ac\'b6\'f8\'bd\'ab\'d2\'bb\'d0\'a9\'b2\'bd\'d6\'e8\'d1\'d3\'b3\'d9\'b5\'bd\'d7\'d3\'c0\'e0\'d6\'d0\'a1\'a3\'c4\'a3\'b0\'e5\'b7\'bd\'b7\'a8\'ca\'b9\'b5\'c3\'d7\'d3\'c0\'e0\'bf\'c9\'d2\'d4\'d4\'da\'b2\'bb\'b8\'c4\'b1\'e4\'cb\'e3\'b7\'a8\'bd\'e1\'b9\'b9\'b5\'c4\'c7\'e9\'bf\'f6\'cf\'c2\'a3\'ac\'d6\'d8\'d0\'c2\'b6\'a8\'d2\'e5\'cb\'e3\'b7\'a8\'d6\'d0\'b5\'c4\'c4\'b3\'d0\'a9\'b2\'bd\'d6\'e8\'a1\'a3} 916 | 917 | 918 | 919 | title 920 | 921 | constrainedWidth 922 | 300 923 | htmlText 924 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>模板方法模式</p> 925 | shrinkToFitContent 926 | 1 927 | text 928 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 929 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 930 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 931 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 932 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 933 | 934 | \f0\fs36 \cf2 \'c4\'a3\'b0\'e5\'b7\'bd\'b7\'a8\'c4\'a3\'ca\'bd} 935 | 936 | 937 | 938 | contentAlignment 939 | 1 940 | fillColor 941 | {1.000, 1.000, 1.000, 1.000} 942 | isDecreasingBranchThickness 943 | 944 | isDrawingFill 945 | 946 | isLeftAligned 947 | 948 | location 949 | {336.203125, 299.15234375} 950 | nodeID 951 | 23654D44-6652-4014-A3FE-A806EA745C4A 952 | strokeColor 953 | {0.144, 0.670, 1.000, 1.000} 954 | strokeStyle 955 | 0 956 | strokeWidth 957 | 5 958 | subnodes 959 | 960 | 961 | contentAlignment 962 | 1 963 | fillColor 964 | {1.000, 1.000, 1.000, 1.000} 965 | isDecreasingBranchThickness 966 | 967 | isDrawingFill 968 | 969 | isLeftAligned 970 | 971 | location 972 | {499.203125, 274.15234375} 973 | nodeID 974 | 1C1462B0-86DE-4BCF-A97D-54E641838E6B 975 | strokeColor 976 | {0.144, 0.670, 1.000, 1.000} 977 | strokeStyle 978 | 0 979 | strokeWidth 980 | 4 981 | subnodes 982 | 983 | title 984 | 985 | constrainedWidth 986 | 300 987 | htmlText 988 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>提供一种方法顺序访问一个聚合对象中各个元素 , 而又不需暴露该对象的内部表示。</p> 989 | shrinkToFitContent 990 | 1 991 | text 992 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 993 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 994 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 995 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 996 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 997 | 998 | \f0\fs36 \cf2 \'cc\'e1\'b9\'a9\'d2\'bb\'d6\'d6\'b7\'bd\'b7\'a8\'cb\'b3\'d0\'f2\'b7\'c3\'ce\'ca\'d2\'bb\'b8\'f6\'be\'db\'ba\'cf\'b6\'d4\'cf\'f3\'d6\'d0\'b8\'f7\'b8\'f6\'d4\'aa\'cb\'d8 , \'b6\'f8\'d3\'d6\'b2\'bb\'d0\'e8\'b1\'a9\'c2\'b6\'b8\'c3\'b6\'d4\'cf\'f3\'b5\'c4\'c4\'da\'b2\'bf\'b1\'ed\'ca\'be\'a1\'a3} 999 | 1000 | 1001 | 1002 | title 1003 | 1004 | constrainedWidth 1005 | 300 1006 | htmlText 1007 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>迭代器模式</p> 1008 | shrinkToFitContent 1009 | 1 1010 | text 1011 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1012 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1013 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1014 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1015 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1016 | 1017 | \f0\fs36 \cf2 \'b5\'fc\'b4\'fa\'c6\'f7\'c4\'a3\'ca\'bd} 1018 | 1019 | 1020 | 1021 | contentAlignment 1022 | 1 1023 | fillColor 1024 | {1.000, 1.000, 1.000, 1.000} 1025 | isDecreasingBranchThickness 1026 | 1027 | isDrawingFill 1028 | 1029 | isLeftAligned 1030 | 1031 | location 1032 | {336.203125, 390.15234375} 1033 | nodeID 1034 | C0EE2485-9BB5-4A19-8496-2A9AF3118654 1035 | strokeColor 1036 | {0.144, 0.670, 1.000, 1.000} 1037 | strokeStyle 1038 | 0 1039 | strokeWidth 1040 | 5 1041 | subnodes 1042 | 1043 | 1044 | contentAlignment 1045 | 1 1046 | fillColor 1047 | {1.000, 1.000, 1.000, 1.000} 1048 | isDecreasingBranchThickness 1049 | 1050 | isDrawingFill 1051 | 1052 | isLeftAligned 1053 | 1054 | location 1055 | {481.203125, 365.15234375} 1056 | nodeID 1057 | 6527DC84-4480-4659-86DE-8D514E5F56C1 1058 | strokeColor 1059 | {0.144, 0.670, 1.000, 1.000} 1060 | strokeStyle 1061 | 0 1062 | strokeWidth 1063 | 4 1064 | subnodes 1065 | 1066 | title 1067 | 1068 | constrainedWidth 1069 | 300 1070 | htmlText 1071 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。</p> 1072 | shrinkToFitContent 1073 | 1 1074 | text 1075 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1076 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1077 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1078 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1079 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1080 | 1081 | \f0\fs36 \cf2 \'d4\'ca\'d0\'ed\'d2\'bb\'b8\'f6\'b6\'d4\'cf\'f3\'d4\'da\'c6\'e4\'c4\'da\'b2\'bf\'d7\'b4\'cc\'ac\'b8\'c4\'b1\'e4\'ca\'b1\'b8\'c4\'b1\'e4\'cb\'fc\'b5\'c4\'d0\'d0\'ce\'aa\'a3\'ac\'b6\'d4\'cf\'f3\'bf\'b4\'c6\'f0\'c0\'b4\'cb\'c6\'ba\'f5\'d0\'de\'b8\'c4\'c1\'cb\'cb\'fc\'b5\'c4\'c0\'e0\'a1\'a3} 1082 | 1083 | 1084 | 1085 | title 1086 | 1087 | constrainedWidth 1088 | 300 1089 | htmlText 1090 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>行为模式</p> 1091 | shrinkToFitContent 1092 | 1 1093 | text 1094 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1095 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1096 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1097 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1098 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1099 | 1100 | \f0\fs36 \cf2 \'d0\'d0\'ce\'aa\'c4\'a3\'ca\'bd} 1101 | 1102 | 1103 | 1104 | title 1105 | 1106 | constrainedWidth 1107 | 300 1108 | htmlText 1109 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>行为型模式</p> 1110 | shrinkToFitContent 1111 | 1 1112 | text 1113 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1114 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1115 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1116 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1117 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1118 | 1119 | \f0\fs36 \cf2 \'d0\'d0\'ce\'aa\'d0\'cd\'c4\'a3\'ca\'bd} 1120 | 1121 | 1122 | 1123 | contentAlignment 1124 | 1 1125 | fillColor 1126 | {1.000, 1.000, 1.000, 1.000} 1127 | isDecreasingBranchThickness 1128 | 1129 | isDrawingFill 1130 | 1131 | isLeftAligned 1132 | 1133 | location 1134 | {-163.796875, 134.15234375} 1135 | nodeID 1136 | 500731CA-F319-4094-9A71-9DFA530D81F8 1137 | strokeColor 1138 | {1.000, 0.742, 0.041, 1.000} 1139 | strokeStyle 1140 | 0 1141 | strokeWidth 1142 | 6 1143 | subnodes 1144 | 1145 | 1146 | contentAlignment 1147 | 1 1148 | fillColor 1149 | {1.000, 1.000, 1.000, 1.000} 1150 | isDecreasingBranchThickness 1151 | 1152 | isDrawingFill 1153 | 1154 | isLeftAligned 1155 | 1156 | location 1157 | {-326.796875, -2.34765625} 1158 | nodeID 1159 | 38B84B48-5150-4132-86FA-CC9637C1AD43 1160 | strokeColor 1161 | {1.000, 0.742, 0.041, 1.000} 1162 | strokeStyle 1163 | 0 1164 | strokeWidth 1165 | 5 1166 | subnodes 1167 | 1168 | 1169 | contentAlignment 1170 | 1 1171 | fillColor 1172 | {1.000, 1.000, 1.000, 1.000} 1173 | isDecreasingBranchThickness 1174 | 1175 | isDrawingFill 1176 | 1177 | isLeftAligned 1178 | 1179 | location 1180 | {-687.796875, -14.84765625} 1181 | nodeID 1182 | 8FD69D9D-8DF2-41F0-A5B7-3688764C4787 1183 | strokeColor 1184 | {1.000, 0.742, 0.041, 1.000} 1185 | strokeStyle 1186 | 0 1187 | strokeWidth 1188 | 4 1189 | subnodes 1190 | 1191 | title 1192 | 1193 | constrainedWidth 1194 | 300 1195 | htmlText 1196 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>将一个类的接口转换成客户希望的另外一个接口。</p> 1197 | shrinkToFitContent 1198 | 1 1199 | text 1200 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1201 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1202 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1203 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1204 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1205 | 1206 | \f0\fs36 \cf2 \'bd\'ab\'d2\'bb\'b8\'f6\'c0\'e0\'b5\'c4\'bd\'d3\'bf\'da\'d7\'aa\'bb\'bb\'b3\'c9\'bf\'cd\'bb\'a7\'cf\'a3\'cd\'fb\'b5\'c4\'c1\'ed\'cd\'e2\'d2\'bb\'b8\'f6\'bd\'d3\'bf\'da\'a1\'a3} 1207 | 1208 | 1209 | 1210 | title 1211 | 1212 | constrainedWidth 1213 | 300 1214 | htmlText 1215 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>适配器模式</p> 1216 | shrinkToFitContent 1217 | 1 1218 | text 1219 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1220 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1221 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1222 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1223 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1224 | 1225 | \f0\fs36 \cf2 \'ca\'ca\'c5\'e4\'c6\'f7\'c4\'a3\'ca\'bd} 1226 | 1227 | 1228 | 1229 | contentAlignment 1230 | 1 1231 | fillColor 1232 | {1.000, 1.000, 1.000, 1.000} 1233 | isDecreasingBranchThickness 1234 | 1235 | isDrawingFill 1236 | 1237 | isLeftAligned 1238 | 1239 | location 1240 | {-308.796875, 76.15234375} 1241 | nodeID 1242 | CF88B84A-42E9-4131-9FA3-F7276D66E6EE 1243 | strokeColor 1244 | {1.000, 0.742, 0.041, 1.000} 1245 | strokeStyle 1246 | 0 1247 | strokeWidth 1248 | 5 1249 | subnodes 1250 | 1251 | 1252 | contentAlignment 1253 | 1 1254 | fillColor 1255 | {1.000, 1.000, 1.000, 1.000} 1256 | isDecreasingBranchThickness 1257 | 1258 | isDrawingFill 1259 | 1260 | isLeftAligned 1261 | 1262 | location 1263 | {-669.796875, 51.15234375} 1264 | nodeID 1265 | 56618C36-BFE8-4F3A-B7CB-EB7F57E9C84F 1266 | strokeColor 1267 | {1.000, 0.742, 0.041, 1.000} 1268 | strokeStyle 1269 | 0 1270 | strokeWidth 1271 | 4 1272 | subnodes 1273 | 1274 | title 1275 | 1276 | constrainedWidth 1277 | 300 1278 | htmlText 1279 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。</p> 1280 | shrinkToFitContent 1281 | 1 1282 | text 1283 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1284 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1285 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1286 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1287 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1288 | 1289 | \f0\fs36 \cf2 \'cc\'e1\'b9\'a9\'c1\'cb\'d2\'bb\'b8\'f6\'cd\'b3\'d2\'bb\'b5\'c4\'bd\'d3\'bf\'da\'a3\'ac\'d3\'c3\'c0\'b4\'b7\'c3\'ce\'ca\'d7\'d3\'cf\'b5\'cd\'b3\'d6\'d0\'b5\'c4\'d2\'bb\'c8\'ba\'bd\'d3\'bf\'da\'a1\'a3\'cd\'e2\'b9\'db\'b6\'a8\'d2\'e5\'c1\'cb\'d2\'bb\'b8\'f6\'b8\'df\'b2\'e3\'bd\'d3\'bf\'da\'a3\'ac\'c8\'c3\'d7\'d3\'cf\'b5\'cd\'b3\'b8\'fc\'c8\'dd\'d2\'d7\'ca\'b9\'d3\'c3\'a1\'a3} 1290 | 1291 | 1292 | 1293 | title 1294 | 1295 | constrainedWidth 1296 | 300 1297 | htmlText 1298 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>外观模式</p> 1299 | shrinkToFitContent 1300 | 1 1301 | text 1302 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1303 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1304 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1305 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1306 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1307 | 1308 | \f0\fs36 \cf2 \'cd\'e2\'b9\'db\'c4\'a3\'ca\'bd} 1309 | 1310 | 1311 | 1312 | contentAlignment 1313 | 1 1314 | fillColor 1315 | {1.000, 1.000, 1.000, 1.000} 1316 | isDecreasingBranchThickness 1317 | 1318 | isDrawingFill 1319 | 1320 | isLeftAligned 1321 | 1322 | location 1323 | {-308.796875, 179.65234375} 1324 | nodeID 1325 | FC69EF21-847B-4241-9A90-445656BC23E5 1326 | strokeColor 1327 | {1.000, 0.742, 0.041, 1.000} 1328 | strokeStyle 1329 | 0 1330 | strokeWidth 1331 | 5 1332 | subnodes 1333 | 1334 | 1335 | contentAlignment 1336 | 1 1337 | fillColor 1338 | {1.000, 1.000, 1.000, 1.000} 1339 | isDecreasingBranchThickness 1340 | 1341 | isDrawingFill 1342 | 1343 | isLeftAligned 1344 | 1345 | location 1346 | {-669.796875, 142.15234375} 1347 | nodeID 1348 | C3820864-E17C-4FA5-A662-05B2B51AF49A 1349 | strokeColor 1350 | {1.000, 0.742, 0.041, 1.000} 1351 | strokeStyle 1352 | 0 1353 | strokeWidth 1354 | 4 1355 | subnodes 1356 | 1357 | title 1358 | 1359 | constrainedWidth 1360 | 300 1361 | htmlText 1362 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>将对象组合成树形结构以表示 &quot;部分-整体&quot; 的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。</p> 1363 | shrinkToFitContent 1364 | 1 1365 | text 1366 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1367 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1368 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1369 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1370 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1371 | 1372 | \f0\fs36 \cf2 \'bd\'ab\'b6\'d4\'cf\'f3\'d7\'e9\'ba\'cf\'b3\'c9\'ca\'f7\'d0\'ce\'bd\'e1\'b9\'b9\'d2\'d4\'b1\'ed\'ca\'be "\'b2\'bf\'b7\'d6-\'d5\'fb\'cc\'e5" \'b5\'c4\'b2\'e3\'b4\'ce\'bd\'e1\'b9\'b9\'a1\'a3Composite \'ca\'b9\'b5\'c3\'d3\'c3\'bb\'a7\'b6\'d4\'b5\'a5\'b8\'f6\'b6\'d4\'cf\'f3\'ba\'cd\'d7\'e9\'ba\'cf\'b6\'d4\'cf\'f3\'b5\'c4\'ca\'b9\'d3\'c3\'be\'df\'d3\'d0\'d2\'bb\'d6\'c2\'d0\'d4\'a1\'a3} 1373 | 1374 | 1375 | 1376 | title 1377 | 1378 | constrainedWidth 1379 | 300 1380 | htmlText 1381 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>组合模式</p> 1382 | shrinkToFitContent 1383 | 1 1384 | text 1385 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1386 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1387 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1388 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1389 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1390 | 1391 | \f0\fs36 \cf2 \'d7\'e9\'ba\'cf\'c4\'a3\'ca\'bd} 1392 | 1393 | 1394 | 1395 | contentAlignment 1396 | 1 1397 | fillColor 1398 | {1.000, 1.000, 1.000, 1.000} 1399 | isDecreasingBranchThickness 1400 | 1401 | isDrawingFill 1402 | 1403 | isLeftAligned 1404 | 1405 | location 1406 | {-308.796875, 270.65234375} 1407 | nodeID 1408 | 3D6072FA-0BB9-4AE5-A3B8-0FBA62B7AF3F 1409 | strokeColor 1410 | {1.000, 0.742, 0.041, 1.000} 1411 | strokeStyle 1412 | 0 1413 | strokeWidth 1414 | 5 1415 | subnodes 1416 | 1417 | 1418 | contentAlignment 1419 | 1 1420 | fillColor 1421 | {1.000, 1.000, 1.000, 1.000} 1422 | isDecreasingBranchThickness 1423 | 1424 | isDrawingFill 1425 | 1426 | isLeftAligned 1427 | 1428 | location 1429 | {-669.796875, 258.15234375} 1430 | nodeID 1431 | CAC5D50C-64E4-4B10-A2FC-B27823F174D1 1432 | strokeColor 1433 | {1.000, 0.742, 0.041, 1.000} 1434 | strokeStyle 1435 | 0 1436 | strokeWidth 1437 | 4 1438 | subnodes 1439 | 1440 | title 1441 | 1442 | constrainedWidth 1443 | 300 1444 | htmlText 1445 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>为其他对象提供一种代理以控制对这个对象的访问。</p> 1446 | shrinkToFitContent 1447 | 1 1448 | text 1449 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1450 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1451 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1452 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1453 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1454 | 1455 | \f0\fs36 \cf2 \'ce\'aa\'c6\'e4\'cb\'fb\'b6\'d4\'cf\'f3\'cc\'e1\'b9\'a9\'d2\'bb\'d6\'d6\'b4\'fa\'c0\'ed\'d2\'d4\'bf\'d8\'d6\'c6\'b6\'d4\'d5\'e2\'b8\'f6\'b6\'d4\'cf\'f3\'b5\'c4\'b7\'c3\'ce\'ca\'a1\'a3} 1456 | 1457 | 1458 | 1459 | title 1460 | 1461 | constrainedWidth 1462 | 300 1463 | htmlText 1464 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>代理模式</p> 1465 | shrinkToFitContent 1466 | 1 1467 | text 1468 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1469 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1470 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1471 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1472 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1473 | 1474 | \f0\fs36 \cf2 \'b4\'fa\'c0\'ed\'c4\'a3\'ca\'bd} 1475 | 1476 | 1477 | 1478 | title 1479 | 1480 | constrainedWidth 1481 | 300 1482 | htmlText 1483 | <p style='color: rgba(91, 91, 91, 1.000000); font: 18px "PingFang SC"; -cocoa-font-postscriptname: "PingFangSC-Regular"; '>结构型模式</p> 1484 | shrinkToFitContent 1485 | 1 1486 | text 1487 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1488 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;} 1489 | {\colortbl;\red255\green255\blue255;\red91\green91\blue91;} 1490 | {\*\expandedcolortbl;;\csgenericrgb\c35686\c35686\c35686;} 1491 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1492 | 1493 | \f0\fs36 \cf2 \'bd\'e1\'b9\'b9\'d0\'cd\'c4\'a3\'ca\'bd} 1494 | 1495 | 1496 | 1497 | title 1498 | 1499 | constrainedWidth 1500 | 300 1501 | htmlText 1502 | <p style='color: rgba(21, 122, 150, 1.000000); font: 21px "PingFang SC"; text-align: left; -cocoa-font-postscriptname: "PingFangSC-Light"; '>设计模式</p> 1503 | shrinkToFitContent 1504 | 1 1505 | text 1506 | {\rtf1\ansi\ansicpg936\cocoartf1504\cocoasubrtf820 1507 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Light;} 1508 | {\colortbl;\red255\green255\blue255;\red21\green122\blue150;} 1509 | {\*\expandedcolortbl;;\csgenericrgb\c8235\c47843\c58824;} 1510 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 1511 | 1512 | \f0\fs42 \cf2 \'c9\'e8\'bc\'c6\'c4\'a3\'ca\'bd} 1513 | 1514 | 1515 | 1516 | 1517 | printInfo 1518 | 1519 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE 1520 | hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpCJKEhIQITlNT 1521 | dHJpbmcBlIQBKxZOU0hvcml6b250YWxseUNlbnRlcmVkhpKEhIQITlNOdW1iZXIAhIQH 1522 | TlNWYWx1ZQCUhAEqhIQBY50BhpKEmZkNTlNSaWdodE1hcmdpboaShJuchIQBZp5IhpKE 1523 | mZkMTlNMZWZ0TWFyZ2luhpKfkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSbnISX 1524 | lwKGkoSZmRROU1ZlcnRpY2FsUGFnaW5hdGlvboaShJucpJcAhpKEmZkUTlNWZXJ0aWNh 1525 | bGx5Q2VudGVyZWSGkpqShJmZC05TVG9wTWFyZ2luhpKEm5ygnlqGkoSZmQ5OU0JvdHRv 1526 | bU1hcmdpboaSqYaG 1527 | 1528 | title 1529 | 设计模式 1530 | version 1531 | 4 1532 | 1533 | 1534 | -------------------------------------------------------------------------------- /desgin-patterns-cheet.mindnode/style.mindnodestyle/contents.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengxiaowai/py-patterns/867ef54c34994752afd77fd0ac54b99567ccfa52/desgin-patterns-cheet.mindnode/style.mindnodestyle/contents.xml -------------------------------------------------------------------------------- /desgin-patterns-cheet.mindnode/style.mindnodestyle/metadata.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengxiaowai/py-patterns/867ef54c34994752afd77fd0ac54b99567ccfa52/desgin-patterns-cheet.mindnode/style.mindnodestyle/metadata.plist -------------------------------------------------------------------------------- /desgin-patterns-cheet.mindnode/viewState.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengxiaowai/py-patterns/867ef54c34994752afd77fd0ac54b99567ccfa52/desgin-patterns-cheet.mindnode/viewState.plist -------------------------------------------------------------------------------- /desgin-patterns-cheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengxiaowai/py-patterns/867ef54c34994752afd77fd0ac54b99567ccfa52/desgin-patterns-cheet.png -------------------------------------------------------------------------------- /docs/behavioral/command.md: -------------------------------------------------------------------------------- 1 | ## 命令模式 2 | 3 | ### 定义 4 | 5 | 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。 6 | 7 | ### 动机 8 | 9 | 有时必须向某对象提交请求,但并不知道关于被请求的操作或请求的接受者的任何信息。 10 | 11 | ### 适用性 12 | 13 | - 抽象出待执行的动作参数化某对象(调用者和实现者解耦)。 14 | - 在不同时候制定、排列和执行请求。 15 | - 支持取消操作。 16 | - 支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。 17 | - 用构建在原语操作上的高层操作构造一个系统(事物)。 18 | 19 | ### 实现 20 | 21 | ```python 22 | #!/usr/bin/env python3 23 | # -*- coding: utf-8 -*- 24 | 25 | 26 | class Transaction(object): 27 | def __init__(self): 28 | self.commands = [] 29 | self.success = [] 30 | 31 | def add_command(self, command): 32 | self.commands.append(command) 33 | 34 | def excute(self): 35 | """ 调用者不需要知道执行什么,只知道有 excute 方法""" 36 | for command in self.commands: 37 | command.excute() 38 | self.success.append(command) 39 | 40 | def undo(self): 41 | for command in self.success[::-1]: 42 | command.undo() 43 | 44 | 45 | class CreateCommand(object): 46 | def __init__(self, filename): 47 | self.filename = filename 48 | 49 | def excute(self): 50 | print('create a {}'.format(self.filename)) 51 | 52 | def undo(self): 53 | print('delete this {}'.format(self.filename)) 54 | 55 | 56 | class WriteCommand(object): 57 | def __init__(self, filename, content): 58 | self.filename = filename 59 | self.content = content 60 | 61 | def excute(self): 62 | print('write [{}] to {}'.format(self.content, self.filename)) 63 | 64 | def undo(self): 65 | print('remove [{}] from {}'.format(self.content, self.filename)) 66 | 67 | 68 | class ChomdCommand(object): 69 | def __init__(self, filename, mode): 70 | self.filename = filename 71 | self.mode = mode 72 | 73 | def excute(self): 74 | print('change {} mode to {}'.format(self.filename, self.mode)) 75 | 76 | def undo(self): 77 | print('revocer {} mode to {}'.format(self.filename, '644')) 78 | 79 | 80 | class MoveCommand(object): 81 | """ 假设这个命令发生了错误 """ 82 | 83 | def __init__(self, filename, to_path): 84 | self.filename = filename 85 | self.to_path = to_path 86 | 87 | def excute(self): 88 | print('move {} to {}'.format(self.filename, self.to_path)) 89 | raise Exception('you have not permission') 90 | 91 | def undo(self): 92 | print('move {} to {}'.format(self.to_path, self.filename)) 93 | 94 | 95 | if __name__ == '__main__': 96 | create_command = CreateCommand('test.file') 97 | write_command = WriteCommand('test.file', 'my name is zhengxiaowai') 98 | chmod_command = ChomdCommand('test.file', '600') 99 | 100 | file_operation = Transaction() 101 | file_operation.add_command(create_command) 102 | file_operation.add_command(write_command) 103 | file_operation.add_command(chmod_command) 104 | 105 | # file_operation.excute() 106 | 107 | try: 108 | # 发生错误恢复原始状态 109 | move_command = MoveCommand('test.file', '/etc/') 110 | file_operation.add_command(move_command) 111 | file_operation.excute() 112 | except: 113 | print('\nraise a error, start to undo:\n') 114 | file_operation.undo() 115 | ``` -------------------------------------------------------------------------------- /docs/behavioral/iterator.md: -------------------------------------------------------------------------------- 1 | ## 迭代器模式 2 | 3 | ### 定义 4 | 5 | 提供一种方法顺序访问一个聚合对象中各个元素 , 而又不需暴露该对象的内部表示。 6 | 7 | ### 动机 8 | 9 | 不同的对象有不同的遍历方式,即使可以 预见到所需的那些遍历操作,你可能也不希望列表的接口中充斥着各种不同遍历的操作。 10 | 有时还可能需要在同一个表列上同时进行多个遍历。 11 | 12 | ### 适用性 13 | 14 | - 访问一个聚合对象的内容而无需暴露它的内部表示。 15 | - 支持对聚合对象的多种遍历。 16 | - 为遍历不同的聚合结构提供一个统一的接口 (即, 支持多态迭代)。 17 | 18 | ### 实现 19 | 20 | ```python 21 | #!/usr/bin/env python3 22 | # -*- coding: utf-8 -*- 23 | 24 | 25 | class BreakfastMenu(object): 26 | def __init__(self): 27 | self.items = [] 28 | 29 | def add_item(self, name, price): 30 | self.items.append((name, price)) 31 | 32 | def __iter__(self): 33 | """ return a Iterable object """ 34 | return iter(self.items) 35 | 36 | 37 | class LaunchMenu(object): 38 | def __init__(self): 39 | self.items = set() 40 | 41 | def add_item(self, name, price): 42 | self.items.add((name, price)) 43 | 44 | def __iter__(self): 45 | """ return a Iterable object """ 46 | return iter(self.items) 47 | 48 | 49 | class DinnerMenu(object): 50 | def __init__(self): 51 | self.items = {} 52 | 53 | def add_item(self, name, price): 54 | self.items[name] = price 55 | 56 | def __iter__(self): 57 | """ return a Iterable object """ 58 | return iter(((name, price) for name, price in self.items.items())) 59 | 60 | 61 | if __name__ == '__main__': 62 | breakfast_menu = BreakfastMenu() 63 | breakfast_menu.add_item('milk', 5) 64 | breakfast_menu.add_item('bread', 6) 65 | breakfast_menu.add_item('coffee', 7) 66 | breakfast_menu.add_item('donuts', 3) 67 | 68 | print('\nBreakfastMenu:') 69 | for item in breakfast_menu: 70 | print(item) 71 | 72 | launch_menu = LaunchMenu() 73 | launch_menu.add_item('milk', 5) 74 | launch_menu.add_item('bread', 6) 75 | launch_menu.add_item('coffee', 7) 76 | launch_menu.add_item('donuts', 3) 77 | 78 | print('\nLaunchMenu:') 79 | for item in launch_menu: 80 | print(item) 81 | 82 | dinner_menu = DinnerMenu() 83 | dinner_menu.add_item('milk', 5) 84 | dinner_menu.add_item('bread', 6) 85 | dinner_menu.add_item('coffee', 7) 86 | dinner_menu.add_item('donuts', 3) 87 | 88 | print('\nDinnerMenu:') 89 | for item in dinner_menu: 90 | print(item) 91 | ``` -------------------------------------------------------------------------------- /docs/behavioral/observer.md: -------------------------------------------------------------------------------- 1 | ## 观察者模式 2 | 3 | ### 定义 4 | 5 | 定义对象间的一种一对多的依赖关系 ,当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并被自动更新。 6 | 7 | ### 动机 8 | 9 | 将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。 10 | 11 | ### 适用性 12 | 13 | - 当一个抽象模型有两个方面 , 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。 14 | - 当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。 15 | - 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的。 16 | 17 | ### 优缺点 18 | 19 | - 目标和观察者间的抽象耦合 20 | - 支持广播通信 21 | - 意外的更新 22 | 23 | ### 实现 24 | 25 | > 有一个气象站可以获取温度、湿度、氧气的数据,和一些面板,每当数据更新时候要显示在面板上 —— 《Head First 设计模式》 26 | 27 | ```python 28 | class AbstractObservable(object): 29 | def register(self): 30 | raise NotImplementedError( 31 | 'register is a abstract method which must be implemente') 32 | 33 | def remove(self): 34 | raise NotImplementedError( 35 | 'remove is a abstract method which must be implemente') 36 | ``` 37 | 38 | 观察者这观察的对象,称作可观察对象,该抽象类需要实现具体的注册和删除观察者管理方法。 39 | 40 | ```python 41 | class AbstractDisplay(object): 42 | def update(self): 43 | raise NotImplementedError( 44 | 'update is a abstract method which must be implemente') 45 | 46 | def display(self): 47 | raise NotImplementedError( 48 | 'display is a abstract method which must be implemente') 49 | ``` 50 | 51 | 观察者抽象类,需要实现 update 方法,让可观察对象可以通知观察者。 52 | 53 | ```python 54 | class Subject(object): 55 | def __init__(self, subject): 56 | self.subject = subject 57 | self._observers = [] 58 | 59 | def register(self, ob): 60 | self._observers.append(ob) 61 | 62 | def remove(self, ob): 63 | self._observers.remove(ob) 64 | 65 | def notify(self, data=None): 66 | for ob in self._observers: 67 | ob.update(data) 68 | ``` 69 | 70 | 此外还实现了一个 Subject 用于管理多个事件的通知,可以称作可观察对象管理者。 71 | 72 | ```python 73 | class WeatherData(AbstractObservable): 74 | def __init__(self, *namespaces): 75 | self._nss = {} 76 | self._clock = None 77 | self._temperature = None 78 | self._humidity = None 79 | self._oxygen = None 80 | 81 | for ns in namespaces: 82 | self._nss[ns] = Subject(ns) 83 | 84 | def register(self, ns, ob): 85 | if ns not in self._nss: 86 | raise Exception('this {} is invalid namespace'.format(ns)) 87 | self._nss[ns].register(ob) 88 | 89 | def remove(self, ns, ob): 90 | return self._nss[ns].remove(ob) 91 | 92 | def set_measurement(self, data): 93 | # 此处实现可以更加紧凑,但是为了表达更简单,采用如下方式 94 | self._clock = data['clock'] 95 | self._temperature = data['temperature'] 96 | self._humidity = data['humidity'] 97 | self._oxygen = data['oxygen'] 98 | 99 | for k in self._nss.keys(): 100 | if k != 'all': 101 | data = self 102 | 103 | self._nss[k].notify(data) 104 | 105 | # 以下 property 为了实现 pull 模式 106 | 107 | @property 108 | def clock(self): 109 | return self._clock 110 | 111 | @property 112 | def temperature(self): 113 | return self._temperature 114 | 115 | @property 116 | def humidity(self): 117 | return self._humidity 118 | @property 119 | def oxygen(self): 120 | return self._oxygen 121 | 122 | ``` 123 | 124 | 观察者模式的可观察对象实现可以分成两种实现方案: 125 | 126 | - push 模式 127 | - pull 模式 128 | 129 | push 模式能保证所有的观察者可以接收到全部的数据,无论需要不需要,频繁更新会影响性能。 130 | 131 | pull 模式需要观察者自己拉去数据,实现起来比较容易出错,但是能按需获取信息。 132 | 133 | ```python 134 | class OverviewDisplay(AbstractDisplay): 135 | def __init__(self): 136 | self._data = {} 137 | 138 | def update(self, data): 139 | self._data = data 140 | self.display() 141 | 142 | def display(self): 143 | print(u'总览显示面板:') 144 | for k, v in self._data.items(): 145 | print(k + ': ' + str(v)) 146 | ``` 147 | 148 | 这是一个总览的 Display ,采用 push 模式更新,获取当前能获取的所有数据,并且显示出来。 149 | 150 | ```python 151 | class TemperatureDisplay(AbstractDisplay): 152 | def __init__(self): 153 | self._storage = [] 154 | 155 | def update(self, data): 156 | dt = data.clock 157 | temperature = data.temperature 158 | self._storage.append((dt, temperature)) 159 | self.display() 160 | 161 | def display(self): 162 | print(u'温度显示面板:') 163 | for storey in self._storage: 164 | print(storey[0] + ': ' + str(storey[1])) 165 | ``` 166 | 167 | 一个只会显示温度的 Display,能观察到时间和温度变化,由于只关心温度数据,所以采用 pull 模式更加合适。 168 | 169 | ```python 170 | if __name__ == '__main__': 171 | import time 172 | 173 | # 生成一个可观察对象,支持('all', 'temperature', 'humidity', 'oxygen')的数据通知 174 | wd = WeatherData('all', 'temperature', 'humidity', 'oxygen') 175 | 176 | # 两个观察者对象 177 | od = OverviewDisplay() 178 | td = TemperatureDisplay() 179 | 180 | # 注册到可观察对象中,能获取数据更新 181 | wd.register('all', od) 182 | wd.register('temperature', td) 183 | 184 | # 更新数据,可观察对象将会自动更新数据 185 | wd.set_measurement({ 186 | 'clock': time.strftime("%Y-%m-%d %X", time.localtime()), 187 | 'temperature': 20, 188 | 'humidity': 60, 189 | 'oxygen': 10 190 | }) 191 | 192 | # 一秒后再次更新数据 193 | time.sleep(1) 194 | print('\n') 195 | wd.set_measurement({ 196 | 'clock': time.strftime("%Y-%m-%d %X", time.localtime()), 197 | 'temperature': 21, 198 | 'humidity': 58, 199 | 'oxygen': 7 200 | }) 201 | ``` 202 | 203 | 执行的结果如下: 204 | 205 | ```shell 206 | 总览显示面板: 207 | humidity: 60 208 | temperature: 20 209 | oxygen: 10 210 | clock: 2017-03-26 18:08:41 211 | 温度显示面板: 212 | 2017-03-26 18:08:41: 20 213 | 214 | 总览显示面板: 215 | humidity: 58 216 | temperature: 21 217 | oxygen: 7 218 | clock: 2017-03-26 18:08:42 219 | 温度显示面板: 220 | 2017-03-26 18:08:41: 20 221 | 2017-03-26 18:08:42: 21 222 | ``` 223 | 224 | 一秒后数据更新,两个面板会自动更新数据。 225 | 226 | > Python 设计模式相关代码可以 https://github.com/zhengxiaowai/design-patterns 获得。 227 | > 228 | > 该模式的代码可以从 https://raw.githubusercontent.com/zhengxiaowai/design-patterns/master/behavioral/observer.py 获得 229 | 230 | 当需要一个湿度面板时候也是只需要生成这个面板、并且实现你所需要的 update、display 方法然后再注册到可观察对象中即可,无须修改其他部分,实现了结构的解耦。 231 | 232 | 观察者模式在很多软件和框架中经常出现,比如 MVC 框架,事件的循环等应用场景。若希望在一个对象的状态变化时能够通知/提醒所有相关者(一个对象或一组对象),则可以使用观察者模式。观察者模式的一个重要特性是,在运行时,订阅者/观察者的数量以及观察者是谁可能会变化,也可以改变。 233 | -------------------------------------------------------------------------------- /docs/behavioral/state.md: -------------------------------------------------------------------------------- 1 | ## 状态模式 2 | 3 | ### 定义 4 | 5 | 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。 6 | 7 | ### 动机 8 | 9 | 事物存在有限的不同状态,并且可以在状态中互相切换,作为相应的行为。 10 | 11 | ### 适用性 12 | 13 | - 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。 14 | - 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。 15 | 16 | ### 实现 17 | 18 | ```python 19 | #!/usr/bin/env python 20 | # -*- coding: utf-8 -*- 21 | 22 | 23 | class State(object): 24 | def __init__(self, process): 25 | self.process = process 26 | 27 | def execute(self): 28 | raise NotImplementedError('you must implemment this method') 29 | 30 | def handup(self): 31 | raise NotImplementedError('you must implemment this method') 32 | 33 | def killed(self): 34 | raise NotImplementedError('you must implemment this method') 35 | 36 | 37 | class ProcessError(Exception): 38 | pass 39 | 40 | 41 | class CreatedState(State): 42 | def execute(self): 43 | print('execute process, transform to running state') 44 | self.process.set_state(self.process.running_state) 45 | 46 | def handup(self): 47 | print('handup process, transform to waitting state') 48 | self.process.set_state(self.process.waitting_state) 49 | 50 | def killed(self): 51 | print('killed process, transform to waitting teminated') 52 | self.process.set_state(self.process.terminated_state) 53 | 54 | 55 | class WaittingState(State): 56 | def execute(self): 57 | print('execute process, transform to running state') 58 | self.process.set_state(self.process.running_state) 59 | 60 | def handup(self): 61 | print('handup process, transform to waitting state') 62 | self.process.set_state(self.process.waitting_state) 63 | 64 | def killed(self): 65 | print('killed process, transform to waitting teminated') 66 | self.process.set_state(self.process.terminated_state) 67 | 68 | 69 | class RunningState(State): 70 | def execute(self): 71 | raise ProcessError('running state have not execute method') 72 | 73 | def handup(self): 74 | raise ProcessError('running state have not handup method') 75 | 76 | def killed(self): 77 | print('killed process, transform to waitting teminated') 78 | self.process.set_state(self.process.terminated_state) 79 | 80 | 81 | class TerminateState(State): 82 | def execute(self): 83 | raise ProcessError('running state have not execute method') 84 | 85 | def handup(self): 86 | raise ProcessError('running state have not handup method') 87 | 88 | def killed(self): 89 | print('process was teminated') 90 | self.process.set_state(self.process.terminated_state) 91 | 92 | 93 | class Process(object): 94 | def __init__(self, name): 95 | self.created_state = CreatedState(self) 96 | self.waitting_state = WaittingState(self) 97 | self.running_state = RunningState(self) 98 | self.terminated_state = TerminateState(self) 99 | 100 | self.name = name 101 | self.state = self.created_state 102 | 103 | def __str__(self): 104 | return self.state.__class__.__name__ 105 | 106 | def set_state(self, state): 107 | self.state = state 108 | 109 | def execute(self): 110 | self.state.execute() 111 | 112 | def handup(self): 113 | self.state.handup() 114 | 115 | def killed(self): 116 | self.state.killed() 117 | 118 | 119 | if __name__ == '__main__': 120 | print('Process NO.1') 121 | p1 = Process('p1') 122 | p1.execute() 123 | p1.killed() 124 | 125 | print('\nProcess NO.2') 126 | p2 = Process('p2') 127 | p2.handup() 128 | p2.execute() 129 | p2.killed() 130 | 131 | print('\nProcess NO.3') 132 | p3 = Process('p3') 133 | p3.handup() 134 | p3.handup() 135 | p3.killed() 136 | 137 | print('\nProcess NO.4') 138 | p4 = Process('p4') 139 | p4.killed() 140 | ``` 141 | 142 | -------------------------------------------------------------------------------- /docs/behavioral/strategy.md: -------------------------------------------------------------------------------- 1 | ## 策略模式 2 | 3 | ### 定义 4 | 5 | 定义一系列算法,把他们封装起来,并且可以相互替换使用,使得算法可以独立于客户端而变化。 6 | 7 | ### 适用性 8 | 9 | - 许多相关类仅仅只有算法不同 10 | - 需要使用使用一个算法的不用变体 11 | - 算法使用客户不应该知道的数据 12 | - 一个类定义了多种行为 13 | 14 | ### 优缺点 15 | 16 | - 一系列可重用的算法或者行为 17 | - 一种替代继承的方法 18 | - 消除一些条件语句 19 | - 可以选择不同的行为或者算法 20 | - 客户端要知道策略的不同地方 21 | 22 | ### 实现 23 | 24 | > 年底了,需要发年终奖,年终奖需要根据本年度的绩效来决定拿多少,绩效的等级有 S、A、B 三种。 25 | > 实现一个计算每个人年终奖的程序,后期可能会添加 S+、C 等级或者更多。 26 | 27 | #### Python Class 28 | 29 | ```python 30 | #!/usr/bin/env python 31 | # -*- coding: utf-8 -*- 32 | 33 | # 定义一系列计算年终奖的算法 34 | bouns_strategy = { 35 | 'S': lambda s: s * 4, 36 | 'A': lambda s: s * 3, 37 | 'B': lambda s: s * 2, 38 | 39 | # 添加 S+ 和 C 算法 40 | 'SP': lambda s: s * 5, 41 | 'C': lambda s: s , 42 | } 43 | 44 | 45 | class Bouns: 46 | def __init__(self, name, salary): 47 | self.name = name 48 | self.salary = salary 49 | # 计算方法通过属性来设定,这样可以容易被替换 50 | self.calculate = None 51 | 52 | def __str__(self): 53 | return "{} get {}".format(self.name, self.bouns) 54 | 55 | @property 56 | def bouns(self): 57 | return self.calculate(self.salary) 58 | 59 | 60 | if __name__ == '__main__': 61 | jack_bouns = Bouns('jack', 10000) 62 | jack_bouns.calculate = bouns_strategy['S'] 63 | print(jack_bouns) 64 | 65 | linda_bouns = Bouns('linda', 10000) 66 | linda_bouns.calculate = bouns_strategy['A'] 67 | print(linda_bouns) 68 | 69 | sean_bouns = Bouns('sean', 10000) 70 | sean_bouns.calculate = bouns_strategy['B'] 71 | print(sean_bouns) 72 | 73 | # 现在需求变化了,添加 S+ 作为最高级,C 级 作为最低级 74 | # jack 从 S 调整到 S+ 75 | # sean 从 B 调整到 C 76 | print('需求改变以后......') 77 | 78 | jack_bouns.calculate = bouns_strategy['SP'] 79 | print(jack_bouns) 80 | 81 | print(linda_bouns) 82 | 83 | sean_bouns.calculate = bouns_strategy['C'] 84 | print(sean_bouns) 85 | 86 | # 从上面的计算年终的算法可以看出 87 | # 需求改变以后只需要替代原来算法就可实现了 88 | ``` 89 | 90 | #### Python Function 91 | 92 | ```python 93 | #!/usr/bin/env python 94 | # -*- coding: utf-8 -*- 95 | 96 | # 定义一系列计算年终奖的算法 97 | bouns_strategy = { 98 | 'S': lambda s: s * 4, 99 | 'A': lambda s: s * 3, 100 | 'B': lambda s: s * 2, 101 | 102 | # 添加 S+ 和 C 算法 103 | 'SP': lambda s: s * 5, 104 | 'C': lambda s: s, 105 | } 106 | 107 | 108 | def calculate_bouns(name, strategy, salary): 109 | return '{name} get {salary}'.format(name=name, salary=strategy(salary)) 110 | 111 | 112 | if __name__ == '__main__': 113 | print(calculate_bouns('jack', bouns_strategy['S'], 10000)) 114 | print(calculate_bouns('linda', bouns_strategy['A'], 10000)) 115 | print(calculate_bouns('sean', bouns_strategy['B'], 10000)) 116 | 117 | # 现在需求变化了,添加 S+ 作为最高级,C 级 作为最低级 118 | # jack 从 S 调整到 S+ 119 | # sean 从 B 调整到 C 120 | print('需求改变以后......') 121 | 122 | print(calculate_bouns('jack', bouns_strategy['SP'], 10000)) 123 | print(calculate_bouns('linda', bouns_strategy['A'], 10000)) 124 | print(calculate_bouns('sean', bouns_strategy['C'], 10000)) 125 | ``` -------------------------------------------------------------------------------- /docs/behavioral/templete.md: -------------------------------------------------------------------------------- 1 | ## 模板方法模式 2 | 3 | ### 定义 4 | 5 | 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。 6 | 7 | ### 动机 8 | 9 | 设计一个应用框架,这个框架按照固定的流程实现,但是某些方法需要子类来提供。也可以提供钩子,让子类来决定做什么。 10 | 11 | ### 适用性 12 | 13 | - 一次性实现一个算法的不变部分,将可变的行为留给子类实现。 14 | - 各子类中公共方法的行为应被提取出来并集中到一个公共父类中以避免代码重复。 15 | - 控制子类扩展,在特定的点调用钩子操作,只允许在这些点进行扩展。 16 | 17 | ### 实现 18 | 19 | ```python 20 | #!/usr/bin/env python 21 | # -*- coding: utf-8 -*- 22 | 23 | from abc import ABCMeta, abstractmethod 24 | 25 | 26 | class CaffeineBeverage(metaclass=ABCMeta): 27 | def make_beverage(self): 28 | self.boil_water() 29 | self.brew() 30 | self.pour_in_cup() 31 | if (self.customer_want_condiments()): 32 | self.add_condiments() 33 | 34 | def boil_water(self): 35 | print('把水烧开') 36 | 37 | def pour_in_cup(self): 38 | print('倒入杯子中') 39 | 40 | def customer_want_condiments(self): 41 | # hook 42 | return False 43 | 44 | @abstractmethod 45 | def brew(self): 46 | pass 47 | 48 | @abstractmethod 49 | def add_condiments(self): 50 | pass 51 | 52 | 53 | class Tea(CaffeineBeverage): 54 | def brew(self): 55 | print('用沸水浸泡茶叶') 56 | 57 | def customer_want_condiments(self): 58 | return True 59 | 60 | def add_condiments(self): 61 | print('添加柠檬') 62 | 63 | 64 | class Coffee(CaffeineBeverage): 65 | def brew(self): 66 | print('用沸水冲泡咖啡') 67 | 68 | def customer_want_condiments(self): 69 | return False 70 | 71 | def add_condiments(self): 72 | print('添加牛奶和糖') 73 | 74 | 75 | if __name__ == '__main__': 76 | print('制作咖啡:') 77 | coffee = Coffee() 78 | coffee.make_beverage() 79 | print('\n制作茶:') 80 | tea = Tea() 81 | tea.make_beverage() 82 | ``` -------------------------------------------------------------------------------- /docs/creational/abstract_factory.md: -------------------------------------------------------------------------------- 1 | ## 抽象工厂 2 | 3 | ### 定义 4 | 5 | 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 6 | 7 | ### 动机 8 | 9 | 创建一系列相关的类,每一类都有一个抽象类,其子类负责具体实现。 10 | 11 | ### 适用性 12 | 13 | 在以下情况可以使用 Abstract Factory模式: 14 | 15 | - 一个系统要独立于它的产品的创建、组合和表示时。 16 | - 一个系统要由多个产品系列中的一个来配置时。 17 | - 当你要强调一系列相关的产品对象的设计以便进行联合使用时。 18 | - 当你提供一个产品类库,而只想显示它们的接口而不是实现时。 19 | 20 | ### 优缺点 21 | 22 | - 易于添加新的抽象子类 23 | - 难于添加新的抽象类 24 | - 数量庞大的类难以管理 25 | 26 | ### 实现 27 | 28 | ```python 29 | #!/usr/bin/env python3 30 | # -*- coding: utf-8 -*- 31 | 32 | from abc import ABC, abstractmethod 33 | 34 | 35 | class PizzaIngredientFactory(ABC): 36 | @abstractmethod 37 | def create_dougth(self): 38 | pass 39 | 40 | @abstractmethod 41 | def create_sauce(self): 42 | pass 43 | 44 | @abstractmethod 45 | def create_cheese(self): 46 | pass 47 | 48 | @abstractmethod 49 | def create_vegies(self): 50 | pass 51 | 52 | @abstractmethod 53 | def create_pepperoni(self): 54 | pass 55 | 56 | @abstractmethod 57 | def create_clam(self): 58 | pass 59 | 60 | 61 | class NYPizzaIngredientFactory(PizzaIngredientFactory): 62 | def __init__(self): 63 | self._location = type(self).__name__ 64 | 65 | def create_dougth(self): 66 | return self._location + ' dougth' 67 | 68 | def create_sauce(self): 69 | return self._location + ' sauce' 70 | 71 | def create_cheese(self): 72 | return self._location + ' cheese' 73 | 74 | def create_vegies(self): 75 | return self._location + ' vegies' 76 | 77 | def create_pepperoni(self): 78 | return self._location + ' pepperoni' 79 | 80 | def create_clam(self): 81 | return self._location + ' clam' 82 | 83 | 84 | class ChicagoPizzaIngredientFactory(PizzaIngredientFactory): 85 | def __init__(self): 86 | self._location = type(self).__name__ 87 | 88 | def create_dougth(self): 89 | return self._location + ' dougth' 90 | 91 | def create_sauce(self): 92 | return self._location + ' sauce' 93 | 94 | def create_cheese(self): 95 | return self._location + ' cheese' 96 | 97 | def create_vegies(self): 98 | return self._location + ' vegies' 99 | 100 | def create_pepperoni(self): 101 | return self._location + ' pepperoni' 102 | 103 | def create_clam(self): 104 | return self._location + ' clam' 105 | 106 | 107 | class Pizza(ABC): 108 | def __init__(self): 109 | self._dougth = '' 110 | self._sauce = '' 111 | self._cheese = '' 112 | self._vegies = '' 113 | self._pepperoni = '' 114 | self._clam = '' 115 | 116 | @abstractmethod 117 | def prepare(self): 118 | pass 119 | 120 | def bake(self): 121 | print('烘焙...') 122 | 123 | def cut(self): 124 | print('切片...') 125 | 126 | def box(self): 127 | print('装盒...') 128 | 129 | 130 | class CheesePizza(Pizza): 131 | def __init__(self, factory): 132 | super(CheesePizza, self).__init__() 133 | self._factory = factory 134 | 135 | def prepare(self): 136 | print('准备 CheesePizza 中...') 137 | self._dougth = self._factory.create_dougth() 138 | self._sauce = self._factory.create_sauce() 139 | self._cheese = self._factory.create_cheese() 140 | 141 | def __str__(self): 142 | return 'CheesePizza 有: {}, {}, {}'.format( 143 | self._dougth, self._sauce, self._cheese) 144 | 145 | 146 | class ClamPizza(Pizza): 147 | 148 | def __init__(self, factory): 149 | super(ClamPizza, self).__init__() 150 | self._factory = factory 151 | 152 | def prepare(self): 153 | print('准备 ClamPizza 中...') 154 | self._dougth = self._factory.create_dougth() 155 | self._sauce = self._factory.create_sauce() 156 | self._cheese = self._factory.create_cheese() 157 | self._clam = self._factory.create_clam() 158 | 159 | def __str__(self): 160 | return 'CheesePizza 有: {}, {}, {}, {}'.format( 161 | self._dougth, self._sauce, self._cheese, self._clam) 162 | 163 | 164 | class PizzaStore(ABC): 165 | def order_pizza(self, pizza_type): 166 | pizza = self.create_pizza(pizza_type) 167 | 168 | pizza.prepare() 169 | pizza.bake() 170 | pizza.cut() 171 | pizza.box() 172 | 173 | return pizza 174 | 175 | @abstractmethod 176 | def create_pizza(self): 177 | pass 178 | 179 | 180 | class NYPizzaStore(PizzaStore): 181 | def create_pizza(self, item): 182 | ny_pizza_ingredient_factory = NYPizzaIngredientFactory() 183 | if item == 'cheese': 184 | return CheesePizza(ny_pizza_ingredient_factory) 185 | elif item == 'clam': 186 | return ClamPizza(ny_pizza_ingredient_factory) 187 | 188 | 189 | class ChicagoPizzaStore(PizzaStore): 190 | def create_pizza(self, item): 191 | chicago_pizza_ingredient_factory = ChicagoPizzaIngredientFactory() 192 | if item == 'cheese': 193 | return CheesePizza(chicago_pizza_ingredient_factory) 194 | elif item == 'clam': 195 | return ClamPizza(chicago_pizza_ingredient_factory) 196 | 197 | 198 | if __name__ == '__main__': 199 | # 纽约披萨店 200 | ny_pizza_store = NYPizzaStore() 201 | ny_pizza1 = ny_pizza_store.order_pizza('cheese') 202 | print(ny_pizza1) 203 | 204 | ny_pizza2 = ny_pizza_store.order_pizza('clam') 205 | print(ny_pizza1) 206 | 207 | # 芝加哥披萨店 208 | chicago_pizza_store = ChicagoPizzaStore() 209 | chicago_pizza1 = chicago_pizza_store.order_pizza('cheese') 210 | print(chicago_pizza1) 211 | 212 | chicago_pizza2 = chicago_pizza_store.order_pizza('clam') 213 | print(chicago_pizza1) 214 | 215 | ``` -------------------------------------------------------------------------------- /docs/creational/factory_method.md: -------------------------------------------------------------------------------- 1 | ## 工厂方法 2 | 3 | ### 定义 4 | 5 | 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类实例化延迟到其子类。 6 | 7 | ### 动机 8 | 9 | 框架使用抽象类定义和维护对象之间的关系。这些对象的创建通常也由框架负责。 10 | 11 | ### 适用性 12 | 13 | - 当一个类不知道它所必须创建的对象的类的时候。 14 | - 当一个类希望由它的子类来指定它所创建的对象的时候。 15 | - 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。 16 | 17 | ### 优缺点 18 | 19 | - 不绑定特定应用相关的类到代码中。 20 | - 需要为每一个特定情况创建一个子类 21 | 22 | ### 实现 23 | 24 | > 有两个披萨店,提供纽约风味披萨和芝加哥风味披萨——《Head First 设计模式》 25 | 26 | ```python 27 | #!/usr/bin/env python 28 | # -*- coding: utf-8 -*- 29 | 30 | from __future__ import unicode_literals, print_function 31 | 32 | 33 | class Pizza(object): 34 | """ Pizza 抽象类 """ 35 | def __init__(self): 36 | self.name = self.getPizzaName() 37 | 38 | def prepare(self): 39 | print('准备...') 40 | 41 | def bake(self): 42 | print('烘焙...') 43 | 44 | def cut(self): 45 | print('切片...') 46 | 47 | def box(self): 48 | print('装盒...') 49 | 50 | 51 | class NYStyleCheesePizza(Pizza): 52 | """ Pizza 子类 """ 53 | def getPizzaName(self): 54 | return '纽约风味 cheese 披萨' 55 | 56 | 57 | class ChicagoCheesePizza(Pizza): 58 | """ Pizza 子类 """ 59 | def getPizzaName(self): 60 | return '芝加哥风味 cheese 披萨' 61 | 62 | def cut(self): 63 | """ 覆盖父类方法 """ 64 | print('方块切片...') 65 | 66 | 67 | class PizzaStore(object): 68 | def order_pizza(self, pizza_type): 69 | pizza = self.create_pizza(pizza_type) 70 | 71 | pizza.prepare() 72 | pizza.bake() 73 | pizza.cut() 74 | pizza.box() 75 | 76 | return pizza 77 | 78 | 79 | class NYPizzaStore(PizzaStore): 80 | def create_pizza(self, item): 81 | if item == 'cheese': 82 | return NYStyleCheesePizza() 83 | elif item == 'veggie': 84 | # 同上 85 | pass 86 | 87 | 88 | class ChicagoPizzaStore(PizzaStore): 89 | def create_pizza(self, item): 90 | if item == 'cheese': 91 | return ChicagoCheesePizza() 92 | elif item == 'veggie': 93 | # 同上 94 | pass 95 | 96 | 97 | if __name__ == '__main__': 98 | ny_pizza_store = NYPizzaStore() 99 | ny_cheese_pizza = ny_pizza_store.order_pizza('cheese') 100 | print('获得 {}'.format(ny_cheese_pizza.name)) 101 | 102 | print('\n') 103 | 104 | chicago_pizza_store = ChicagoPizzaStore() 105 | chicago_cheese_pizza = chicago_pizza_store.order_pizza('cheese') 106 | print('获得 {}'.format(chicago_cheese_pizza.name)) 107 | ``` -------------------------------------------------------------------------------- /docs/creational/singleton.md: -------------------------------------------------------------------------------- 1 | ## 单例模式 2 | 3 | ### 定义 4 | 5 | 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 6 | 7 | ### 动机 8 | 9 | 在实际编程中,有的时候制造出多个实例,就会导致许多问题的产生。例如,程序的异常行为,资源使用过量,或者是不一致的结果。 10 | 11 | ### 适用性 12 | 13 | - 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。 14 | - 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。 15 | 16 | ### 优缺点 17 | 18 | - 对实例受控访问 19 | - 缩小命名空间 20 | - 允许对操作和表示的精化 21 | - 允许可变数目的实例 22 | - 比类操作更灵活 23 | 24 | ### 实现 25 | 26 | ```python 27 | class Singleton(type): 28 | _instances = {} 29 | def __call__(cls, *args, **kwargs): 30 | if cls not in cls._instances: 31 | cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 32 | return cls._instances[cls] 33 | 34 | class MyClass(object): 35 | __metaclass__ = Singleton 36 | ``` -------------------------------------------------------------------------------- /docs/structural/adapter.md: -------------------------------------------------------------------------------- 1 | 2 | ## 适配器模式 3 | 4 | ### 定义 5 | 6 | 将一个类的接口转换成客户希望的另外一个接口。 7 | 8 | ### 动机 9 | 10 | 有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配。 11 | 12 | ### 适用性 13 | 14 | - 你想使用一个已经存在的类,而它的接口不符合你的需求。 15 | - 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。 16 | - (仅适用于对象 Adapter )你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。 17 | 18 | ### 实现 19 | 20 | ```python 21 | #!/usr/bin/env python3 22 | # -*- coding: utf-8 -*- 23 | 24 | 25 | class Duck(object): 26 | """ 鸭子的动作 """ 27 | 28 | def quack(self): 29 | print('Quack') 30 | 31 | def fly(self): 32 | print('fly') 33 | 34 | 35 | class Turkey(object): 36 | """ 火鸡的动作 """ 37 | 38 | def gobble(self): 39 | print('gobble') 40 | 41 | def fly(self): 42 | print('fly a short distaance') 43 | 44 | 45 | class TurkeyAadpter(object): 46 | """ 火鸡适配器,转化成鸭子 """ 47 | 48 | def __init__(self, turkey): 49 | self.turkey = turkey 50 | 51 | def quack(self): 52 | self.turkey.gobble() 53 | 54 | def fly(self): 55 | """ 火鸡飞行距离是鸭子的五分之一 """ 56 | for _ in range(5): 57 | self.turkey.fly() 58 | 59 | 60 | def duck_activity(duck): 61 | duck.quack() 62 | duck.fly() 63 | 64 | 65 | if __name__ == '__main__': 66 | # 鸭子正常活动 67 | duck = Duck() 68 | duck_activity(duck) 69 | 70 | # 某天鸭子走丢了,一只火鸡冒充了鸭子 71 | turkey = Turkey() 72 | duck_activity(TurkeyAadpter(turkey)) 73 | ``` -------------------------------------------------------------------------------- /docs/structural/composite.md: -------------------------------------------------------------------------------- 1 | ## 组合模式 2 | 3 | ### 定义 4 | 5 | 将对象组合成树形结构以表示 "部分-整体" 的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。 6 | 7 | ### 动机 8 | 9 | 组合对象和单一对象拥有一致性,然客户端可以一起处理。 10 | 11 | ### 适用性 12 | 13 | - 想表示对象的部分 -整体层次结构。 14 | - 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。 15 | 16 | ### 实现 17 | 18 | ```python 19 | #!/usr/bin/env python 20 | # -*- coding: utf-8 -*- 21 | 22 | 23 | class Menu(object): 24 | def __init__(self): 25 | self.items = [] 26 | 27 | def add(self, menu): 28 | self.items.append(menu) 29 | 30 | def printer(self): 31 | for item in self.items: 32 | item.printer() 33 | 34 | 35 | class MenuItem(object): 36 | def __init__(self, name, price): 37 | self.name = name 38 | self.price = price 39 | 40 | def add(self): 41 | raise AttributeError('MenuItem is not supported add methid') 42 | 43 | def printer(self): 44 | print(self.name, self.price) 45 | 46 | 47 | if __name__ == '__main__': 48 | menu = Menu() 49 | 50 | launch_item1 = MenuItem('meet', 15) 51 | launch_item2 = MenuItem('rice', 7) 52 | launch_item3 = MenuItem('noddles', 10) 53 | menu.add(launch_item1) 54 | menu.add(launch_item2) 55 | menu.add(launch_item3) 56 | 57 | drink_menu = Menu() 58 | 59 | drink_item1 = MenuItem('milk', 5) 60 | drink_item2 = MenuItem('tea', 4) 61 | drink_item3 = MenuItem('coffee', 6) 62 | drink_menu.add(drink_item1) 63 | drink_menu.add(drink_item2) 64 | drink_menu.add(drink_item3) 65 | 66 | menu.add(drink_menu) 67 | 68 | menu.printer() 69 | ``` -------------------------------------------------------------------------------- /docs/structural/facade.md: -------------------------------------------------------------------------------- 1 | ## 外观模式 2 | 3 | ### 定义 4 | 5 | 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 6 | 7 | ### 动机 8 | 9 | 将一个系统划分成为若干个子系统有利于降低系统的复杂性。 10 | 11 | ### 适用性 12 | 13 | - 当你要为一个复杂子系统提供一个简单接口时。 14 | - 客户程序与抽象类的实现部分之间存在着很大的依赖性。 15 | - 当你需要构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点 。 16 | 17 | ### 实现 18 | 19 | ```python 20 | #!/usr/bin/env python3 21 | # -*- coding: utf-8 -*- 22 | 23 | 24 | class HardWare(object): 25 | def power_on(self): 26 | print('上电') 27 | 28 | def bootloader(self): 29 | print('bootloader 启动') 30 | 31 | def power_off(self): 32 | print('断电') 33 | 34 | 35 | class OperatingSystem(object): 36 | def load_kernel(self): 37 | print('加载内核') 38 | 39 | def load_image(self): 40 | print('加载镜像') 41 | 42 | def exit_os(self): 43 | print('退出操作系统') 44 | 45 | 46 | class SoftWare(object): 47 | def load_app(self): 48 | print('加载应用程序') 49 | 50 | def exit_app(self): 51 | print('退出应用程序') 52 | 53 | 54 | class Computer(object): 55 | def __init__(self): 56 | self.hw = HardWare() 57 | self.os = OperatingSystem() 58 | self.sw = SoftWare() 59 | 60 | def boot(self): 61 | self.hw.power_on() 62 | self.hw.bootloader() 63 | self.os.load_kernel() 64 | self.os.load_image() 65 | self.sw.load_app() 66 | 67 | def shut_down(self): 68 | self.sw.exit_app() 69 | self.os.exit_os() 70 | self.hw.power_off() 71 | 72 | 73 | if __name__ == '__main__': 74 | computer = Computer() 75 | 76 | print('开机') 77 | computer.boot() 78 | 79 | print('\n关机') 80 | computer.shut_down() 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/structural/proxy.md: -------------------------------------------------------------------------------- 1 | ## 代理模式 2 | 3 | ### 定义 4 | 5 | 为其他对象提供一种代理以控制对这个对象的访问。 6 | 7 | ### 动机 8 | 9 | 对属性和方法的访问控制。 10 | 11 | ### 适用性 12 | 13 | - 远程代理(Remote Proxy)为一个对象在 不同的地址空间 提供局部代表。 14 | - 虚代理(Virtual Proxy)根据需要创建开销很大的对象。 15 | - 保护代理(Protection Proxy)控制对原始对象的访问。 16 | 17 | ### 实现 18 | 19 | ```python 20 | class lazy_property(object): 21 | def __init__(self, fget): 22 | self.fget = fget 23 | self.func_name = fget.__name__ 24 | 25 | def __get__(self, obj, cls): 26 | if obj is None: 27 | return None 28 | value = self.fget(obj) 29 | setattr(obj, self.func_name, value) 30 | return value 31 | 32 | 33 | class Test(object): 34 | 35 | @lazy_property 36 | def results(self): 37 | print('init') 38 | calcs = 5 39 | return calcs 40 | 41 | 42 | t = Test() 43 | print(t.results) 44 | print('') 45 | print(t.results) 46 | ``` -------------------------------------------------------------------------------- /structural/adapter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class Duck(object): 6 | """ 鸭子的动作 """ 7 | 8 | def quack(self): 9 | print('Quack') 10 | 11 | def fly(self): 12 | print('fly') 13 | 14 | 15 | class Turkey(object): 16 | """ 火鸡的动作 """ 17 | 18 | def gobble(self): 19 | print('gobble') 20 | 21 | def fly(self): 22 | print('fly a short distaance') 23 | 24 | 25 | class TurkeyAadpter(object): 26 | """ 火鸡适配器,转化成鸭子 """ 27 | 28 | def __init__(self, turkey): 29 | self.turkey = turkey 30 | 31 | def quack(self): 32 | self.turkey.gobble() 33 | 34 | def fly(self): 35 | """ 火鸡飞行距离是鸭子的五分之一 """ 36 | for _ in range(5): 37 | self.turkey.fly() 38 | 39 | 40 | def duck_activity(duck): 41 | duck.quack() 42 | duck.fly() 43 | 44 | 45 | if __name__ == '__main__': 46 | # 鸭子正常活动 47 | duck = Duck() 48 | duck_activity(duck) 49 | 50 | # 某天鸭子走丢了,一只火鸡冒充了鸭子 51 | turkey = Turkey() 52 | duck_activity(TurkeyAadpter(turkey)) 53 | -------------------------------------------------------------------------------- /structural/composite.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class Menu(object): 6 | def __init__(self): 7 | self.items = [] 8 | 9 | def add(self, menu): 10 | self.items.append(menu) 11 | 12 | def printer(self): 13 | for item in self.items: 14 | item.printer() 15 | 16 | 17 | class MenuItem(object): 18 | def __init__(self, name, price): 19 | self.name = name 20 | self.price = price 21 | 22 | def add(self): 23 | raise AttributeError('MenuItem is not supported add methid') 24 | 25 | def printer(self): 26 | print(self.name, self.price) 27 | 28 | 29 | if __name__ == '__main__': 30 | menu = Menu() 31 | 32 | launch_item1 = MenuItem('meet', 15) 33 | launch_item2 = MenuItem('rice', 7) 34 | launch_item3 = MenuItem('noddles', 10) 35 | menu.add(launch_item1) 36 | menu.add(launch_item2) 37 | menu.add(launch_item3) 38 | 39 | drink_menu = Menu() 40 | 41 | drink_item1 = MenuItem('milk', 5) 42 | drink_item2 = MenuItem('tea', 4) 43 | drink_item3 = MenuItem('coffee', 6) 44 | drink_menu.add(drink_item1) 45 | drink_menu.add(drink_item2) 46 | drink_menu.add(drink_item3) 47 | 48 | menu.add(drink_menu) 49 | 50 | menu.printer() 51 | -------------------------------------------------------------------------------- /structural/facade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | class HardWare(object): 6 | def power_on(self): 7 | print('上电') 8 | 9 | def bootloader(self): 10 | print('bootloader 启动') 11 | 12 | def power_off(self): 13 | print('断电') 14 | 15 | 16 | class OperatingSystem(object): 17 | def load_kernel(self): 18 | print('加载内核') 19 | 20 | def load_image(self): 21 | print('加载镜像') 22 | 23 | def exit_os(self): 24 | print('退出操作系统') 25 | 26 | 27 | class SoftWare(object): 28 | def load_app(self): 29 | print('加载应用程序') 30 | 31 | def exit_app(self): 32 | print('退出应用程序') 33 | 34 | 35 | class Computer(object): 36 | def __init__(self): 37 | self.hw = HardWare() 38 | self.os = OperatingSystem() 39 | self.sw = SoftWare() 40 | 41 | def boot(self): 42 | self.hw.power_on() 43 | self.hw.bootloader() 44 | self.os.load_kernel() 45 | self.os.load_image() 46 | self.sw.load_app() 47 | 48 | def shut_down(self): 49 | self.sw.exit_app() 50 | self.os.exit_os() 51 | self.hw.power_off() 52 | 53 | 54 | if __name__ == '__main__': 55 | computer = Computer() 56 | 57 | print('开机') 58 | computer.boot() 59 | 60 | print('\n关机') 61 | computer.shut_down() 62 | -------------------------------------------------------------------------------- /structural/proxy.py: -------------------------------------------------------------------------------- 1 | class lazy_property(object): 2 | def __init__(self, fget): 3 | self.fget = fget 4 | self.func_name = fget.__name__ 5 | 6 | def __get__(self, obj, cls): 7 | if obj is None: 8 | return None 9 | value = self.fget(obj) 10 | setattr(obj, self.func_name, value) 11 | return value 12 | 13 | 14 | class Test(object): 15 | 16 | @lazy_property 17 | def results(self): 18 | print('init') 19 | calcs = 5 20 | return calcs 21 | 22 | 23 | t = Test() 24 | print(t.results) 25 | print('') 26 | print(t.results) 27 | --------------------------------------------------------------------------------