Classic TM

abstract base class offers "organizing method" which calls "hook methods"

& in ABC, hook methods stay abstract

0 concrete subclasses implement the hooks

0 client code calls organizing method d on some reference to ABC (injecter, or...)

0 which of course refers to a concrete SC

class AbstractBase(object): def orgMethod(self): self.doThis() self.doThat()

class Concrete(AbstractBase): def doThis(self): ... def doThat(self): ...

TM example: paginate text to paginate text, you must:

# remember max number of lines/page

0 output each line, while tracking where you are on the page

0 just before the first line of each page, emit a page header

& just after the last line of each page, emit a page footer class AbstractPager(object):

self.mx = mx self.cur = self.pg = 0 def writeLine(self, line): if self.cur == 0:

self.doHead(self.pg) self.doWrite(line) self.cur += 1 if self.cur >= self.mx: self.doFoot(self.pg) self.cur = 0 self.pg += 1

class PagerStdout(AbstractPager): def doWrite(self, line):

print line def doHead(self, pg):

print 'Page %d:\n\n' % pg+1 def doFoot(self, pg): print '\f', # form-feed character class PagerCurses(AbstractPager):

AbstractPager___init__(self, mx)

self.w.addstr(self.cur, 0, line) def doHead(self, pg): self.w.move(0, 0) self.w.clrtobot() def doFoot(self, pg): self.w.getch() # wait for keypress the "organizing method" provides "structural logic" (sequencing &c)

the "hook methods" perform "actual NNelementary" actions"

it's an often-appropriate factorization of commonality and variation

0 focuses on objects' (classes') responsibilities and collaborations: base class calls hooks, subclass supplies them

® applies the "Hollywood Principle": "don't call us, we'll call you"

class TheBase(object): def doThis(self):

# provide a default (often a no-op) pass def doThat(self):

# or, force subclass to implement

# (might also just be missing...) raise NotlmplementedError

Default implementations often handier, when sensible; but "mandatory" may be good docs.

class AbstractPager(object):

class CursesPager(AbstractPager):

access simply as self.mx -- obviates any need for boilerplate accessors self.getMx()...

def put(self, item): self.not_full.acquire() try:

self.not_full.wait() self._put(item) self.not_empty.notify() finally: self.not_full.release() def _put(self, item): ...

Was this article helpful?

0 0

Post a comment