mirror of
https://github.com/rjNemo/design-patterns
synced 2026-06-06 02:26:40 +00:00
adapter example
This commit is contained in:
parent
7b0e4a5801
commit
cbcb57d42b
6 changed files with 156 additions and 0 deletions
|
|
@ -10,3 +10,5 @@
|
|||
- [Builder](creational/builder/README.md)
|
||||
- [Prototype](creational/prototype/README.md)
|
||||
- [Singleton](creational/singleton/README.md)
|
||||
- [Structural Patterns](structural/README.md)
|
||||
- [Adapter](structural/adapter/README.md)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# Creational Patterns
|
||||
|
||||
Creational patterns provide various object creation mechanisms, which increase flexibility and reuse of existing code.
|
||||
|
||||
- [Factory Method](factory-method/README.md)
|
||||
- [Abstract Factory](abstract-factory/README.md)
|
||||
- [Builder](builder/README.md)
|
||||
|
|
|
|||
5
structural/README.md
Normal file
5
structural/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Structural Patterns
|
||||
|
||||
Structural patterns explain how to assemble objects and classes into larger structures while keeping these structures flexible and efficient.
|
||||
|
||||
- [Adapter](adapter/README.md)
|
||||
36
structural/adapter/README.md
Normal file
36
structural/adapter/README.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Adapter
|
||||
|
||||
Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.
|
||||
|
||||
## Summary
|
||||
|
||||
The Adapter acts as a wrapper between two objects. It catches calls for one object and transforms them to format and interface recognizable by the second object.
|
||||
|
||||
## Problem
|
||||
|
||||
Imagine that you’re creating a stock market monitoring app. The app downloads the stock data from multiple sources in XML format and then displays nice-looking charts and diagrams for the user.
|
||||
|
||||
At some point, you decide to improve the app by integrating a smart 3rd-party analytics library. But there’s a catch: the analytics library only works with data in JSON format.
|
||||
|
||||
You could change the library to work with XML. However, this might break some existing code that relies on the library. And worse, you might not have access to the library’s source code in the first place, making this approach impossible.
|
||||
|
||||
## Solution
|
||||
|
||||
You can create an adapter. This is a special object that converts the interface of one object so that another object can understand it.
|
||||
|
||||
## How to Implement
|
||||
|
||||
1. Make sure that you have at least two classes with incompatible interfaces:
|
||||
|
||||
- A useful service class, which you can’t change (often 3rd-party, legacy or with lots of existing dependencies).
|
||||
- One or several client classes that would benefit from using the service class.
|
||||
|
||||
1. Declare the client interface and describe how clients communicate with the service.
|
||||
|
||||
1. Create the adapter class and make it follow the client interface. Leave all the methods empty for now.
|
||||
|
||||
1. Add a field to the adapter class to store a reference to the service object. The common practice is to initialize this field via the constructor, but sometimes it’s more convenient to pass it to the adapter when calling its methods.
|
||||
|
||||
1. One by one, implement all methods of the client interface in the adapter class. The adapter should delegate most of the real work to the service object, handling only the interface or data format conversion.
|
||||
|
||||
1. Clients should use the adapter via the client interface. This will let you change or extend the adapters without affecting the client code.
|
||||
57
structural/adapter/via_composition.py
Normal file
57
structural/adapter/via_composition.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
class Target:
|
||||
"""
|
||||
The Target defines the domain-specific interface used by the client code.
|
||||
"""
|
||||
|
||||
def request(self) -> str:
|
||||
return "Target: The default target's behavior."
|
||||
|
||||
|
||||
class Adaptee:
|
||||
"""
|
||||
The Adaptee contains some useful behavior, but its interface is
|
||||
incompatible with the existing client code. The Adaptee needs some
|
||||
adaptation before the client code can use it.
|
||||
"""
|
||||
|
||||
def specific_request(self) -> str:
|
||||
return ".eetpadA eht fo roivaheb laicepS"
|
||||
|
||||
|
||||
class Adapter(Target):
|
||||
"""
|
||||
The Adapter makes the Adaptee's interface compatible with the Target's
|
||||
interface via composition.
|
||||
"""
|
||||
|
||||
def __init__(self, adaptee: Adaptee) -> None:
|
||||
self.adaptee = adaptee
|
||||
|
||||
def request(self) -> str:
|
||||
return f"Adapter: (TRANSLATED) {self.adaptee.specific_request()[::-1]}"
|
||||
|
||||
|
||||
def client_code(target: Target) -> None:
|
||||
"""
|
||||
The client code supports all classes that follow the Target interface.
|
||||
"""
|
||||
|
||||
print(target.request(), end="")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Client: I can work just fine with the Target objects:")
|
||||
target = Target()
|
||||
client_code(target)
|
||||
print("\n")
|
||||
|
||||
adaptee = Adaptee()
|
||||
print(
|
||||
"Client: The Adaptee class has a weird interface. "
|
||||
"See, I don't understand it:"
|
||||
)
|
||||
print(f"Adaptee: {adaptee.specific_request()}", end="\n\n")
|
||||
|
||||
print("Client: But I can work with it via the Adapter:")
|
||||
adapter = Adapter(adaptee)
|
||||
client_code(adapter)
|
||||
54
structural/adapter/via_inheritance.py
Normal file
54
structural/adapter/via_inheritance.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
class Target:
|
||||
"""
|
||||
The Target defines the domain-specific interface used by the client code.
|
||||
"""
|
||||
|
||||
def request(self) -> str:
|
||||
return "Target: The default target's behavior."
|
||||
|
||||
|
||||
class Adaptee:
|
||||
"""
|
||||
The Adaptee contains some useful behavior, but its interface is
|
||||
incompatible with the existing client code. The Adaptee needs some
|
||||
adaptation before the client code can use it.
|
||||
"""
|
||||
|
||||
def specific_request(self) -> str:
|
||||
return ".eetpadA eht fo roivaheb laicepS"
|
||||
|
||||
|
||||
class Adapter(Target, Adaptee):
|
||||
"""
|
||||
The Adapter makes the Adaptee's interface compatible with the Target's
|
||||
interface via multiple inheritance.
|
||||
"""
|
||||
|
||||
def request(self) -> str:
|
||||
return f"Adapter: (TRANSLATED) {self.specific_request()[::-1]}"
|
||||
|
||||
|
||||
def client_code(target: "Target") -> None:
|
||||
"""
|
||||
The client code supports all classes that follow the Target interface.
|
||||
"""
|
||||
|
||||
print(target.request(), end="")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Client: I can work just fine with the Target objects:")
|
||||
target = Target()
|
||||
client_code(target)
|
||||
print("\n")
|
||||
|
||||
adaptee = Adaptee()
|
||||
print(
|
||||
"""Client: The Adaptee class has a weird interface. See, I don't
|
||||
understand it:"""
|
||||
)
|
||||
print(f"Adaptee: {adaptee.specific_request()}", end="\n\n")
|
||||
|
||||
print("Client: But I can work with it via the Adapter:")
|
||||
adapter = Adapter()
|
||||
client_code(adapter)
|
||||
Loading…
Reference in a new issue