From 8b6329e121c0fe37c8cf39f440080320cd3b9b02 Mon Sep 17 00:00:00 2001 From: chuoru Date: Thu, 30 Jul 2020 19:54:56 +0900 Subject: [PATCH] #1 add decorator study --- DesignPattern/Decorator/README.md | 71 +++++++++++ DesignPattern/Decorator/concept.py | 119 ++++++++++++++++++ DesignPattern/Decorator/duck_typing.py | 17 +++ DesignPattern/Decorator/formatting_tool.py | 67 ++++++++++ DesignPattern/Decorator/runtime_decorators.py | 48 +++++++ DesignPattern/Observer/README.md | 0 DesignPattern/Observer/conceptual.py | 17 +++ 7 files changed, 339 insertions(+) create mode 100644 DesignPattern/Decorator/README.md create mode 100644 DesignPattern/Decorator/concept.py create mode 100644 DesignPattern/Decorator/duck_typing.py create mode 100644 DesignPattern/Decorator/formatting_tool.py create mode 100644 DesignPattern/Decorator/runtime_decorators.py create mode 100644 DesignPattern/Observer/README.md create mode 100644 DesignPattern/Observer/conceptual.py diff --git a/DesignPattern/Decorator/README.md b/DesignPattern/Decorator/README.md new file mode 100644 index 0000000..10d09d4 --- /dev/null +++ b/DesignPattern/Decorator/README.md @@ -0,0 +1,71 @@ +# Decorator + +![real world analogy](https://refactoring.guru/images/patterns/content/decorator/decorator-comic-1.png) + +Thuộc trong nhóm các mô hình cấu trúc (Structural Pattern), Decorator cung cấp +công cụ để thêm vào đối tượng những chức năng mới. + +Cách thức thực hiện: Đặt đối tượng vào những cái bọc (wrapper) đặc biệt đã được chuẩn +bị sẵn những chức muốn thêm. + +## Mô hình cấu trúc (Structural Pattern) + +Mô hình giải thích cách để tập hợp đối tượng và lớp thành một cấu trúc lớn, đồng thời +duy trì sự linh hoạt và tính hiệu quả. + +## Phân biệt Python's Decorators và Decorator Pattern + +Decorator Pattern giúp lập trình viên thêm các chức năng mới vào một đối tượng có +trước một cách linh động. Khi bạn "trang trí" một đối tượng (instance), bạn chỉ mở rộng chức +năng của đối tượng đó chức không ảnh hưởng tới các đối tượng khác có cùng lớp (class) + +Trong khi đó, Python Decorators thêm chức năng vào các hàm tại thời điểm định nghĩa hàm, +thường không được sử dụng trong thời gian chạy. + +```python +def identity(ob): + return ob + +@identity +def myfunc(): + print "my function" + +myfunc() +print(myfunc) + +# Output: +# my function +# +``` + +![decorator illustrator](https://refactoring.guru/images/patterns/diagrams/decorator/structure.png) + +## Example + +Ví dụ lấy từ nguồn: https://www.geeksforgeeks.org/decorator-method-python-design-patterns/ + +### Formatting tool for Text + +![Normal](https://media.geeksforgeeks.org/wp-content/uploads/20200202224344/Decorator-1.png) + +![Bold](https://media.geeksforgeeks.org/wp-content/uploads/20200202224449/Decorator-2.png) + +![Bold & Underline](https://media.geeksforgeeks.org/wp-content/uploads/20200202224528/Decorator-3.png) + +###Advantage +- ***Quy tắc đơn trách nghiệm***: Chia một lớp với nhiều chức năng phức tạp thành những chức +năng đơn giản được gói lại trong các Decorator Pattern. +- ***Khả năng xử lí trong thời gian chạy***: Có thể thêm hoặc xoá Decorate Pattern. +- ***Thay thấy việc lớp con (Sub Classing)***: Thay vì thêm các lớp con tại thời điểm định dạng đối tượng, +Decorator Pattern có thể dùng trong thời gian chạy. + +###Disadvantage +- ***Phức tạp***: Cấu trúc lớp xếp lớp của một chuỗi Decorate Pattern sẽ khiến phần đối tượng ban đầu bị +thay đổi quá nhiều. +- ***Không gọn gàng*** + +###Ứng dụng +- ***Không thể kế thừa***: Decorate Pattern sẽ được sử dụng trong các trường hợp không thể kế thừa để mở +rộng chức năng của đối tượng. + +- ***Sử dụng trong thời gian chạy***: có thể gán các chức năng khác nhau và độc lập cho đối tượng. diff --git a/DesignPattern/Decorator/concept.py b/DesignPattern/Decorator/concept.py new file mode 100644 index 0000000..11c6ecc --- /dev/null +++ b/DesignPattern/Decorator/concept.py @@ -0,0 +1,119 @@ +# coding: utf-8 +""" + +Abstract:: + - +History:: + - Ver. Date Author History + - +Copyright (C) 2020 HACHIX Corporation. All Rights Reserved. +""" +# 標準ライブラリ + + +# 関連外部ライブラリ + + +# 内部ライブラリ + + +class Component(): + """ + The base Component interface defines operations that can be altered by + decorators. + """ + + def operation(self) -> str: + pass + + +class ConcreteComponent(Component): + """ + Concrete Components provide default implementations of the operations. There + might be several variations of these classes. + """ + + def operation(self) -> str: + return "ConcreteComponent" + + +class Decorator(Component): + """ + The base Decorator class follows the same interface as the other components. + The primary purpose of this class is to define the wrapping interface for + all concrete decorators. The default implementation of the wrapping code + might include a field for storing a wrapped component and the means to + initialize it. + """ + + _component: Component = None + + def __init__(self, component: Component) -> None: + self._component = component + + @property + def component(self) -> str: + """ + The Decorator delegates all work to the wrapped component. + """ + + return self._component + + def operation(self) -> str: + return self._component.operation() + + +class ConcreteDecoratorA(Decorator): + """ + Concrete Decorators call the wrapped object and alter its result in some + way. + """ + + def operation(self) -> str: + """ + Decorators may call parent implementation of the operation, instead of + calling the wrapped object directly. This approach simplifies extension + of decorator classes. + """ + return f"ConcreteDecoratorA({self.component.operation()})" + + +class ConcreteDecoratorB(Decorator): + """ + Decorators can execute their behavior either before or after the call to a + wrapped object. + """ + + def operation(self) -> str: + return f"ConcreteDecoratorB({self.component.operation()})" + + +def client_code(component: Component) -> None: + """ + The client code works with all objects using the Component interface. This + way it can stay independent of the concrete classes of components it works + with. + """ + + # ... + + print(f"RESULT: {component.operation()}", end="") + + # ... + + +if __name__ == "__main__": + # This way the client code can support both simple components... + simple = ConcreteComponent() + print("Client: I've got a simple component:") + client_code(simple) + print("\n") + + # ...as well as decorated ones. + # + # Note how decorators can wrap not only simple components but the other + # decorators as well. + decorator1 = ConcreteDecoratorA(simple) + decorator2 = ConcreteDecoratorB(decorator1) + print("Client: Now I've got a decorated component:") + client_code(decorator2) diff --git a/DesignPattern/Decorator/duck_typing.py b/DesignPattern/Decorator/duck_typing.py new file mode 100644 index 0000000..857720b --- /dev/null +++ b/DesignPattern/Decorator/duck_typing.py @@ -0,0 +1,17 @@ +# coding: utf-8 +""" + +Abstract:: + - +History:: + - Ver. Date Author History + - +Copyright (C) 2020 HACHIX Corporation. All Rights Reserved. +""" +# 標準ライブラリ + + +# 関連外部ライブラリ + + +# 内部ライブラリ diff --git a/DesignPattern/Decorator/formatting_tool.py b/DesignPattern/Decorator/formatting_tool.py new file mode 100644 index 0000000..a349d63 --- /dev/null +++ b/DesignPattern/Decorator/formatting_tool.py @@ -0,0 +1,67 @@ +# coding: utf-8 +""" + +Abstract:: + - +History:: + - Ver. Date Author History + - +Copyright (C) 2020 HACHIX Corporation. All Rights Reserved. +""" + + +# 標準ライブラリ + + +# 関連外部ライブラリ + + +# 内部ライブラリ + + +class WrittenText: + """Represents a Written text """ + + def __init__(self, text): + self._text = text + + def render(self): + return self._text + + +class UnderlineWrapper(WrittenText): + """Wraps a tag in """ + + def __init__(self, wrapped): + self._wrapped = wrapped + + def render(self): + return "{}".format(self._wrapped.render()) + + +class ItalicWrapper(WrittenText): + """Wraps a tag in """ + + def __init__(self, wrapped): + self._wrapped = wrapped + + def render(self): + return "{}".format(self._wrapped.render()) + + +class BoldWrapper(WrittenText): + """Wraps a tag in """ + + def __init__(self, wrapped): + self._wrapped = wrapped + + def render(self): + return "{}".format(self._wrapped.render()) + + +if __name__ == '__main__': + before_gfg = WrittenText("GeeksforGeeks") + after_gfg = ItalicWrapper(UnderlineWrapper(BoldWrapper(before_gfg))) + + print("before :", before_gfg.render()) + print("after :", after_gfg.render()) diff --git a/DesignPattern/Decorator/runtime_decorators.py b/DesignPattern/Decorator/runtime_decorators.py new file mode 100644 index 0000000..c2cacbc --- /dev/null +++ b/DesignPattern/Decorator/runtime_decorators.py @@ -0,0 +1,48 @@ +# coding: utf-8 +""" + +Abstract:: + - +History:: + - Ver. Date Author History + - +Copyright (C) 2020 HACHIX Corporation. All Rights Reserved. +""" +# 標準ライブラリ + + +# 関連外部ライブラリ + + +# 内部ライブラリ + +def function(string): + return string + + +def decorator(wrapped): + def wrap(string): + # Assume that this is something useful + return wrapped(string.upper()) + return wrap + + +def method_decorator(wrapped): + def wrap(instance, string): + # Assume that this is something useful + return wrapped(instance, string.upper()) + return wrap + + +@decorator +def decorated_function(string): + print('! '.join(string.split(' '))) + + +if __name__ == '__main__': + string = 'Học ăn học nói học gói mang về' + print("Plain function: ", function(string)) # Plain function + print("\nPython decorators") + print("at run time: ", decorator(function)(string)) # Python decorator at run time + print("at definition time", decorated_function(string)) # Python decorator at definition time + diff --git a/DesignPattern/Observer/README.md b/DesignPattern/Observer/README.md new file mode 100644 index 0000000..e69de29 diff --git a/DesignPattern/Observer/conceptual.py b/DesignPattern/Observer/conceptual.py new file mode 100644 index 0000000..857720b --- /dev/null +++ b/DesignPattern/Observer/conceptual.py @@ -0,0 +1,17 @@ +# coding: utf-8 +""" + +Abstract:: + - +History:: + - Ver. Date Author History + - +Copyright (C) 2020 HACHIX Corporation. All Rights Reserved. +""" +# 標準ライブラリ + + +# 関連外部ライブラリ + + +# 内部ライブラリ