Skip to main content
deleted 201 characters in body
Source Link
freakish
  • 3.3k
  • 1
  • 12
  • 16
class ScannerBuilder:
    def __init__(self): 
        self.handlers = {}

    def register(self, obj_type: Type, handler):
        # This could be implemented with just handler parameter,
        # and with inspection magic, but that is just simpler.
        # Although it might be needed anyway for proper validation.

        if obj_type not in self.handlers:
            self.handlers[obj_type] = []
        self.handlers[obj_type].push(handler)

    def build(self) -> Scanner:
        return Scanner(self.handlers)
class ScannerBuilder:
    def __init__(self): 
        self.handlers = {}

    def register(self, obj_type: Type, handler):
        # This could be implemented with just handler parameter,
        # and with inspection magic, but that is just simpler.
        # Although it might be needed anyway for proper validation.

        if obj_type not in self.handlers:
            self.handlers[obj_type] = []
        self.handlers[obj_type].push(handler)

    def build(self) -> Scanner:
        return Scanner(self.handlers)
class ScannerBuilder:
    def __init__(self): 
        self.handlers = {}

    def register(self, obj_type: Type, handler):
        if obj_type not in self.handlers:
            self.handlers[obj_type] = []
        self.handlers[obj_type].push(handler)

    def build(self) -> Scanner:
        return Scanner(self.handlers)
added 69 characters in body
Source Link
freakish
  • 3.3k
  • 1
  • 12
  • 16

Next define a generic abstract handler per object. Not a single abstract handler for all objects. Like this:

builder = ScannerBuilder()
builder.register(Foo, FooScannerfoo_handler)
builder.register(Bar, BarScannerbar_handler)
builder.register(Baz, BazScannerbaz_handler)
builder.register(Baz, OtherBazScannerother_baz_handler)
scanner = builder.build()
scanner.run(input)

Looks like cleanlyclean, separated, easily testable solution to me.

Next define a generic abstract handler:

builder = ScannerBuilder()
builder.register(Foo, FooScanner)
builder.register(Bar, BarScanner)
builder.register(Baz, BazScanner)
builder.register(Baz, OtherBazScanner)
scanner = builder.build()
scanner.run(input)

Looks like cleanly separated solution to me.

Next define a generic abstract handler per object. Not a single abstract handler for all objects. Like this:

builder = ScannerBuilder()
builder.register(Foo, foo_handler)
builder.register(Bar, bar_handler)
builder.register(Baz, baz_handler)
builder.register(Baz, other_baz_handler)
scanner = builder.build()
scanner.run(input)

Looks like clean, separated, easily testable solution to me.

Source Link
freakish
  • 3.3k
  • 1
  • 12
  • 16

Here's how I would approach this. First define each of those entities as separate classes:

class Foo: ...
class Bar: ...
class Baz: ...

Next define a generic abstract handler:

T = TypeVar('T', Foo, Bar, Baz)

class Handler(ABC, Generic[T]):
    @abc.abstractmethod
    def handle(self, obj: T):
        pass

Now we want to store handlers per object type. We will utilize a dict of lists for that. But first lets define a scanner:

class Scanner:
    def __init__(self, handlers):
        # handlers is a dict of lists of Handler instances
        self.handlers = handlers

    def _apply_handlers(self, obj):
        # additional checks and logs here
        obj_type = type(obj)
        for handler in self.handlers[obj_type]:
            handler.handle(obj)

    def run(self, input):
        for chunk in input:
            ... complicated logic ...

            obj = None

            if ... something ...:
                obj = Foo(...)
            if ... something else ...:
                obj = Bar(...)
            if ... something else ...:
                obj = Baz(...)

            if obj is not None:
                self._apply_handlers(obj)
            else:
                # log it?

and finally the corresponding builder:

class ScannerBuilder:
    def __init__(self): 
        self.handlers = {}

    def register(self, obj_type: Type, handler):
        # This could be implemented with just handler parameter,
        # and with inspection magic, but that is just simpler.
        # Although it might be needed anyway for proper validation.

        if obj_type not in self.handlers:
            self.handlers[obj_type] = []
        self.handlers[obj_type].push(handler)

    def build(self) -> Scanner:
        return Scanner(self.handlers)

And finally the usage:

builder = ScannerBuilder()
builder.register(Foo, FooScanner)
builder.register(Bar, BarScanner)
builder.register(Baz, BazScanner)
builder.register(Baz, OtherBazScanner)
scanner = builder.build()
scanner.run(input)

Looks like cleanly separated solution to me.