The appearance model and the flyweight pattern | Python theme on 8/30
Writing in the front
This article is participating in Python Theme Month. See the link for details
This month is Python Activity month, and I decided to try out the daily and random questions in Python for 30 days. Then if I have the energy for the weekend, I’d like to play around with this Python-Patterns
Design mode for me is more learning than my personal experience summary, so I am likely to understand the partial, if there is a boss to see, please timely point out that I choose to write some personal things in Nuggets because of the higher quality of the article here, I do not hope that the later to see these articles are misleading.
The appearance model
The Facade pattern is a way to provide a simpler unified interface to more complex systems. It provides an easier way to access the functionality of the underlying system by providing a single entry point. This abstraction can be seen in many situations in real life. For example, we can turn on a computer with the push of a button, but in reality there are many programs and operations (such as loading programs from disk into memory) when this happens. In this case, the button acts as a unified interface to all the basic programs that start the computer.
Here’s an example:
# Complex computer parts
class CPU:
""" Simple CPU representation. """
def freeze(self) :
print("Freezing processor.")
def jump(self, position) :
print("Jumping to:", position)
def execute(self) :
print("Executing.")
class Memory:
""" Simple memory representation. """
def load(self, position, data) :
print(f"Loading from {position} data: '{data}'.")
class SolidStateDrive:
""" Simple solid state drive representation. """
def read(self, lba, size) :
return f"Some data from sector {lba} with size {size}"
class ComputerFacade:
""" Represents a facade for various computer parts. """
def __init__(self) :
self.cpu = CPU()
self.memory = Memory()
self.ssd = SolidStateDrive()
def start(self) :
self.cpu.freeze()
self.memory.load("0x00", self.ssd.read("100"."1024"))
self.cpu.jump("0x00")
self.cpu.execute()
def main() :
""" >>> computer_facade = ComputerFacade() >>> computer_facade.start() Freezing processor. Loading from 0x00 data: 'Some data from sector 100 with size 1024'. Jumping to: 0x00 Executing. """
if __name__ == "__main__":
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
Copy the code
We see this pattern in the Python standard library when we use the isdir function. Although the user only uses this function to know if a path refers to a directory, the system does something and calls other modules (such as os.stat) to give the result.
The flyweight pattern
The purpose of the share mode is to minimize the number of objects the program needs at runtime. Flyweight is an object shared by multiple contexts, no different from an object that is not shared. The state of a Flyweight should not be affected by its context, which is called its inherent state. Decouple the state of the object from its context, allowing the Flyweight to be shared.
import weakref
class Card:
"""The Flyweight"""
# Could be a simple dict.
# With WeakValueDictionary garbage collection can reclaim the object
# when there are no other references to it.
_pool = weakref.WeakValueDictionary()
def __new__(cls, value, suit) :
# If the object exists in the pool - just return it
obj = cls._pool.get(value + suit)
# otherwise - create new one (and add it to the pool)
if obj is None:
obj = object.__new__(Card)
cls._pool[value + suit] = obj
# This row does the part we usually see in `__init__`
obj.value, obj.suit = value, suit
return obj
# If you uncomment `__init__` and comment-out `__new__` -
# Card becomes normal (non-flyweight).
# def __init__(self, value, suit):
# self.value, self.suit = value, suit
def __repr__(self) :
return f"<Card: {self.value}{self.suit}>"
def main() :
""" >>> c1 = Card('9', 'h') >>> c2 = Card('9', 'h') >>> c1, c2 (
,
) >>> c1 == c2 True >>> c1 is c2 True >>> c1.new_attr = 'temp' >>> c3 = Card('9', 'h') >>> hasattr(c3, 'new_attr') True >>> Card._pool.clear() >>> c4 = Card('9', 'h') >>> hasattr(c4, 'new_attr') False """
if __name__ == "__main__":
import doctest
doctest.testmod()
Copy the code
The example sets up an “object pool” to store initialized objects. When a “card” is created, it first checks to see if it already exists, rather than creating a new one. The goal is to reduce the number of objects initialized by the program. At least here you can see that the design pattern is not conceptually clear-cut, and that the object pool pattern is used unknowingly.
summary
The facade pattern provides a simpler unified interface for complex systems. The meta pattern minimizes memory usage by sharing data with other similar objects.
reference
- Sourcemaking.com/design_patt…
- Fkromer. Making. IO/python – patt…
- Python – 3 – patterns – idioms – test. Readthedocs. IO/en/latest/C…
- Codesnipers.com/?q=python-f…
- Python – patterns. Guide/gang – of – fou…
- Examples from Python ecology