Because the Shape only holds a reference to its Renderer, we can replace that reference while the program runs. The same shape object then produces output from a different backend - no new objects, no subclassing.
Implement Shape.set_renderer(renderer) so it stores the new renderer on self. After calling it, draw() must use the new backend on the very same shape.
class Renderer:
def render_circle(self, radius):
raise NotImplementedError
def render_square(self, side):
raise NotImplementedError
class VectorRenderer(Renderer):
def render_circle(self, radius):
return "vector circle r=" + str(radius)
def render_square(self, side):
return "vector square s=" + str(side)
class RasterRenderer(Renderer):
def render_circle(self, radius):
return "raster pixels for circle r=" + str(radius)
def render_square(self, side):
return "raster pixels for square s=" + str(side)
class Shape:
def __init__(self, renderer):
self.renderer = renderer
def set_renderer(self, renderer):
"""Swap the implementation (renderer) used by this shape at runtime."""
# TODO: store the new renderer on self so later draw() calls use it
pass
def draw(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, renderer, radius):
super().__init__(renderer)
self.radius = radius
def draw(self):
return self.renderer.render_circle(self.radius)
class Square(Shape):
def __init__(self, renderer, side):
super().__init__(renderer)
self.side = side
def draw(self):
return self.renderer.render_square(self.side)
The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.
Because the Shape only holds a reference to its Renderer, we can replace that reference while the program runs. The same shape object then produces output from a different backend - no new objects, no subclassing.
Implement Shape.set_renderer(renderer) so it stores the new renderer on self. After calling it, draw() must use the new backend on the very same shape.
Press Run Tests or ββ© to check your solution.