Closed jhanarato closed 1 year ago
Dale has cast shade on this idea and recommends looking at the double dispatch pattern:
Overall, I think I like the final plan, in particular the notion of having a class that carries an ImageDraw around. I've never used singledispatch, but it certainly seems like it would eliminate a lot of draw_foo methods.
You could address this with a "double-dispatch pattern", ie
class Drawable(Protocol): # or ABC, as you prefer
def draw(self, imageDraw): ...
class Drawing:
def __init__(self, image: ImageDraw):
self._image = image
def draw(self, other: Drawable):
other.draw(self._image) # or maybe just self?
class Text:
...
def draw(self, image):
# however you draw the text on the image
class OtherDrawable: ...
# and so on
This tends to be a bit boiler-plate heavy, but you already (I think) need the Text, etc, classes so it's just changing where the real draw method lives. I've never used double-dispatch (to my recollection) but I think it might be the "classic" oo approach here. As I noted, instead of passing an ImageDraw to the drawables, if Drawing maintains some sort of state, like a defalt color, current position, default font, ..., you might want to pass a Drawing instead.
That's a misunderstanding. Double dispatch doesn't solve any problems. I think I'm OK with single dispatch.
Currently image components have a method to draw themselves. I've felt for a long time that they should instead be drawn on something. I think the way to do this is to TDD a drawing layer. It should have the following features:
This could work like so:
Using
functools.singledispatch()
we can pass in different types such asLine
,Circle
etc.We also need to handle composite types like the DayOfWeekIcon. This has a filled circle and text. This could simply be a sequence of primitives to draw with their offsets.
And we need a way of getting component sizes.