Composition

The reason programmers like using implementation inheritance is because it makes code easier to read since the implementation details of Area are in a separate place than the implementation details of Color. This is nice, because conceivably an object could have a color but not an area, or an area but not a color. The problem, though, is that Square is not really an Area or a Color, but has an area and color. Thus, we should really be using another object oriented technique called composition, which relies on delegation rather than inheritance to break code into small reusable chunks.

Hair Dryer adapter example

class HairDryer:
    def plug(self, socket):
        if socket.voltage() == 120:
            print("I was plugged in properly and am operating.")
        else:
            print("I was plugged in improperly and ")
            print("now you have no hair dryer any more.")

class AmericanSocket:
    def voltage(self):
        return 120

class UKSocket:
    def voltage(self):
        return 240

An Adapter is a class which is constructed with one and only one argument, the “adaptee” or “original” object.

class AdaptToAmericanSocket:
    def __init__(self, original):
        self.original = original

    def voltage(self):
        return self.original.voltage() / 2

So, as you can see, an adapter can ‘override’ the original implementation. It can also ‘extend’ the interface of the original object by providing methods the original object did not have.

an Adapter must explicitly delegate any method calls it does not wish to modify to the original, otherwise the Adapter cannot be used in places where the original is expected.

Interface

is nothing more than a class which is used as a marker.

from zope.interface import Interface

class IAmericanSocket(Interface):
    def voltage():
      """
      Return the voltage produced by this socket object, as an integer.
      """

Notice how it looks just like a regular class definition, other than inheriting from Interface? However, the method definitions inside the class block do not have any method body! Since Python does not have any native language-level support for Interfaces like Java does, this is what distinguishes an Interface definition from a Class.

Now that we have a defined Interface, we can talk about objects using terms like this: “The AmericanSocket class implements the IAmericanSocket interface” and “Please give me an object which adapts UKSocket to the IAmericanSocket interface”. We can make declarations about what interfaces a certain class implements, and we can request adapters which implement a certain interface for a specific class.

from zope.interface import implementer

@implementer(IAmericanSocket)
class AmericanSocket:
    def voltage(self):
        return 120

## or full versoion::


@implementer(IAmericanSocket)
class AdaptToAmericanSocket:
    def __init__(self, original):
        """
        Pass the original UKSocket object as original
        """
        self.original = original

    def voltage(self):
        return self.original.voltage() / 2

TDD In Twisted with Trial

Python’s unit testing framework allows your test class to define a setUp method that is called before each test method in the class. This allows you to add attributes to self that can be used in test methods. There is also a parameterized test method _test()

from calculus.base_2 import Calculation

from twisted.trial import unittest


class CalculationTestCase(unittest.TestCase):
    def setUp(self):
        self.calc = Calculation()

    def _test(self, operation, a, b, expected):
        result = operation(a, b)
        self.assertEqual(result, expected)

    def test_add(self):
        self._test(self.calc.add, 3, 8, 11)

    def test_subtract(self):
        self._test(self.calc.subtract, 7, 3, 4)

    def test_multiply(self):
        self._test(self.calc.multiply, 6, 9, 54)

    def test_divide(self):
        self._test(self.calc.divide, 12, 5, 2)