Notes and exercises for learning design patterns
Practice the core Adapter idea on the smallest useful example.
You are given client code that expects an object with this interface:
reading.sensor_id
reading.timestamp
reading.celsius
But the legacy system gives you a LegacyReading object with a different interface:
legacy.device_id()
legacy.recorded_at()
legacy.temp_f()
Your task is to write an adapter that lets the existing client code use the legacy object without changing the client code.
A greenhouse monitoring service already has alerting logic written against Celsius readings.
Later, the team connects an older gateway. The gateway works, but it reports temperatures in Fahrenheit and uses method names that do not match the new application.
You do not want alerting code to know about Fahrenheit, old method names, or gateway details.
So you will put a small adapter between the old object and the new client code.
Open exercise1.py and implement LegacyReadingAdapter.
The adapter should:
LegacyReading,sensor_id as a property,timestamp as a property,celsius as a property,(fahrenheit - 32) * 5 / 9
For this exercise, round Celsius to two decimal places.
This should work:
legacy = LegacyReading(device="greenhouse-1", when=100, fahrenheit=86.0)
adapted = LegacyReadingAdapter(legacy)
assert adapted.sensor_id == "greenhouse-1"
assert adapted.timestamp == 100
assert adapted.celsius == 30.0
assert alert_if_hot(adapted) is True
The important detail is this:
alert_if_hot(adapted)
The alerting function does not know it received an adapter. It only sees the interface it expects.
python exercise1.py
The file contains basic tests at the bottom.