Structural Design Patterns in Python: A Guide to Flexible and Reusable Code
Learn how to use Structural Design Patterns to create code that is easy to understand and maintain.
Structural Design Patterns are a way to create code that is easy to understand and maintain. They provide a way to assemble objects into complex, easy-to-understand, and maintained structures.
There are five main types of Structural Design Patterns:
- Adapter Pattern
- Bridge Pattern
- Composite Pattern
- Decorator Pattern
- Facade Pattern
Adapter Pattern
The Adapter pattern adapts one interface to another. This can be useful for making it easy to use existing code with new code or for using code from different libraries.
Bridge Pattern
The Bridge pattern decouples an abstraction from its implementation. This can be useful for making it easy to change an abstraction’s implementation without affecting the abstraction’s clients.
Composite Pattern
The Composite pattern represents a hierarchy of objects. This can be useful for making it easy to express complex structures or for making it easy to reuse code.
Decorator Pattern
The Decorator pattern adds new functionality to an existing object. This can be useful for adding logging, caching, or other functionality to objects.
Facade Pattern
The Facade pattern provides a simplified interface to a complex system. This can be useful for making it easy to use a complex system or for hiding the complexity of a complex system from users.
Adapter Pattern
The Adapter pattern is proper when you use two classes with incompatible interfaces. For example, you might have a class that expects to receive a string, but you only have a class that can produce an integer. The Adapter pattern can create a new class that implements the interface expected by the first class but delegates all of its work to the second class.
Bridge Pattern
The Bridge pattern helps decouple the abstraction from its implementation. This can be useful for making it easier to change an abstraction’s implementation without affecting the abstraction’s clients. For example, you might have an abstraction for a car that includes driving, braking, and turning methods. The implementation of these methods might vary depending on the type of Car, such as a sedan or a sports car. The Bridge pattern can be used to create a new class that implements the abstraction for a vehicle but delegates all of its work to a separate class that implements the specific implementation for the type of Car.
Composite Pattern
The Composite pattern is proper when you want to represent a hierarchy of objects. This can be useful for making it easy to express complex structures or for making it easy to reuse code. For example, you might have a hierarchy of shapes, such as a Circle, a Square, and a Rectangle. The Composite pattern can create a new class representing a Shape but also contain other Shapes. This makes it easy to create complex shapes, such as a Circle with a Square inside it.
Decorator Pattern
The Decorator pattern is proper when adding new functionality to an existing object. This can be useful for adding logging, caching, or other functionality to objects. For example, you might have a class that represents a Car. You might want to add a Decorator to the Car that logs all of the actions that the Car performs. This can be done by creating a new class that inherits from the Car class and adds a logging method. The Decorator can then be used to wrap the Car object, and the logging method will be called whenever the Car object is used.
Facade Pattern
The Facade pattern is proper when providing a simplified interface to a complex system. This can be useful for making it easy to use a complex system or for hiding the complexity of a complex system from users. For example, you might have a complex system for managing a database. The Facade pattern can create a new class with a simplified interface for interacting with the database system. This can make it easier for users to use the database system and hide the complexity of the database system from users.
Conclusion
Structural Design Patterns are a valuable tool for software developers. They can help you write better, more maintainable code by creating objects in a more flexible and reusable way.
Code Samples
# Adapter Pattern
class Adapter(object):
def __init__(self, old_object):
self.old_object = old_object
def do_something(self):
return self.old_object.do_something()
class NewObject(object):
def do_something(self):
print("I'm doing something new!")
# Bridge Pattern
class Abstraction(object):
def __init__(self, implementation):
self.implementation = implementation
def operation(self):
return self.implementation.operation()
class ConcreteImplementation1(object):
def operation(self):
print("I'm implementing operation 1")
class ConcreteImplementation2(object):
def operation(self):
print("I'm implementing operation 2")
# Composite Pattern
class Component(object):
def operation(self):
pass
class Leaf(Component):
def operation(self):
print("I'm a leaf")
class Composite(Component):
def __init__(self, children):
self.children = children
def operation(self):
for child in self.children:
child.operation()
# Decorator Pattern
class Decorator(object):
def __init__(self, component):
self.component = component
def operation(self):
self.component.operation()
# Do something else here
# Facade Pattern
class Facade(object):
def __init__(self, system):
self.system = system
def do_something(self):
self.system.do_something()