Card 04/ 05

ExerciseDifficulty: Advanced2 min

Practice: Naming the Structural Pattern From Its Code

Seven short listings, each a wrapper, a tree or a shared object.

Naming a structural pattern from its code comes down to comparing interfaces and counting what is held, and this exercise gives seven listings to practise on, one for each structural pattern, in a mixed order. For each, name the pattern and give the line or feature that decided it.

  1. py
    class XmlToJson:
        def __init__(self, xml_parser):
            self._xml = xml_parser
    
        def to_json(self, text):
            return json.dumps(self._xml.parse_to_dict(text))
  2. py
    class Menu(MenuEntry):
        def price(self):
            return sum(entry.price() for entry in self._entries)
  3. py
    class CompressedStream(Stream):
        def __init__(self, inner: Stream):
            self._inner = inner
    
        def write(self, data):
            self._inner.write(zlib.compress(data))
  4. py
    class IconFactory:
        def icon(self, name):
            if name not in self._icons:
                self._icons[name] = Icon(load_png(name))
            return self._icons[name]
  5. py
    class VideoConverter:
        def convert(self, path, fmt):
            file = VideoFile(path)
            codec = CodecFactory.extract(file)
            audio = AudioMixer().fix(file)
            return BitrateReader.convert(file, codec, audio, fmt)
  6. py
    class LazyImage(Image):
        def draw(self):
            if self._real is None:
                self._real = RealImage(self._path)
            self._real.draw()
  7. py
    class Shape:
        def __init__(self, renderer: Renderer):
            self._renderer = renderer
    
    
    class Circle(Shape): ...
    class Square(Shape): ...
Show the answers
The pattern for each listing, and the deciding feature
ListingPatternThe deciding feature
XmlToJson AdapterOffers to_json over a parser with a different method
Menu CompositeSums price over many entries of its own interface
CompressedStream DecoratorSame write as the stream it holds, with compression added
IconFactory FlyweightReturns one stored icon per name, shared by every caller
VideoConverter FacadeOne convert call over four subsystem classes
LazyImage ProxySame draw, and the real image is created on first use
Shape BridgeShapes vary by subclass and hold a renderer that varies on its own

Listings 3 and 6 are the pair most often swapped: both keep the interface and hold one object. The compressed stream is handed its inner stream and changes the data, so it adds behaviour; the lazy image creates its real image and decides when, so it controls access. Listing 4 is a factory, and what makes it Flyweight is that the icons it returns are shared, which a plain factory would not do.