Structural Patterns

Structural Design Patterns #

Structural Design Patterns are concerned with how classes and objectes can be composed

Python Examples #

Adapter Pattern #

allows the interface of an existing class to be used another interface.

class OldClass:
	def old_method(self):
		return "Old Method"
class Adapter:
	def __init__(self, obj):
		self.obj = obj
	def new_method(self):
		return f"{self.obj.old_method()} plus Adapter"
old_class = OldClass()
adapter = Adapter(old_class)
print(adapter.new_method())

Decorator Pattern #

Allows behaviors to be added to an individual object

class Component:
	def operation(self):
		pass
class ConcreteComponent(Component):
	def operation(self):
		return "ConcreteComponent"
class Decorator(Component):
	def __init__(self, component):
		self._component = component
	def operation(self):
		return self._component.operation()
class ConcreteDecoratorA(Decorator):
	def operation(self):
		return f"ConcreteDecoratorA({self._component.operation()})"
simple = ConcreteComponent()
decorator = ConcreteDecoratorA(simple)
print(decorator.operation())

Composite Pattern #

Composes objects into tree structures to represent part-whole hierachies.

class Component:
	def operation(self):
		pass
class Leaf(Component):
	def operation(self):
		return "Leaf"
class Composite(Component):
	def __init__(self):
		self._children = []
	def add(self, component):
		self._children.append(component)
	def operation(self):
		results = []
		for child in self._children:
			results.append(child.operation())
		return f"Branch({'+'.join(results)})"
simple = Leaf()
tree = Composite()
tree.add(simple)
print(tree.operation())  # Outputs: Branch(Leaf)

Proxy Pattern #

Provides a surrogate or placeholder for another object to control access to it.

class RealImage:
	def __init__(self, filename):
		self.filename = filename
	def load_image_from_disk(self):
		print(f"Loading {self.filename}")
	def display_image(self):
		print(f"Displaying {self.filename}")
class ProxyImage:
	def __init__(self, filename):
		self.filename = filename
		self.real_image = None
	def display_image(self):
		if self.real_image is None:
			self.real_image = RealImage(self.filename)
		self.real_image.display_image()
proxy_image = ProxyImage("test_image.jpg")
proxy_image.display_image()
proxy_image.display_image()

Bridge Pattern #

This pattern decouples an abstraction from its implementation so that the two can vary independently.

Facade Pattern #

This pattern provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. class Subsystem1: def operation1(self): return “Subsystem1: Ready!\n”

Flyweight Pattern #

This pattern uses sharing to support large numbers of fine-grained objects efficiently. A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context — it’s indistinguishable from an instance of the object that’s not shared.