Refactoring the events system for extensibility

The problem with the previous example was that the SystemMonitor class was interacting directly with the concrete classes it was going to retrieve.

In order to achieve a design that honors the open/closed principle, we have to design toward abstractions.

A possible alternative would be to think of this class as it collaborates with the events, and then we delegate the logic for each particular type of event to its corresponding class:

 

Then we have to add a new (polymorphic) method to each type of event with the single responsibility of determining if it corresponds to the data being passed or not, and we also have to change the logic to go through all events, finding the right one.

The new code should look like this:

# openclosed_2.py
class Event:
def __init__(self, raw_data):
self.raw_data = raw_data

@staticmethod
def meets_condition(event_data: dict):
return False


class UnknownEvent(Event):
"""A type of event that cannot be identified from its data"""


class LoginEvent(Event):
@staticmethod
def meets_condition(event_data: dict):
return (
event_data["before"]["session"] == 0
and event_data["after"]["session"] == 1
)


class LogoutEvent(Event):
@staticmethod
def meets_condition(event_data: dict):
return (
event_data["before"]["session"] == 1
and event_data["after"]["session"] == 0
)


class SystemMonitor:
"""Identify events that occurred in the system."""

def __init__(self, event_data):
self.event_data = event_data

def identify_event(self):
for event_cls in Event.__subclasses__():
try:
if event_cls.meets_condition(self.event_data):
return event_cls(self.event_data)
except KeyError:
continue
return UnknownEvent(self.event_data)

Notice how the interaction is now oriented toward an abstraction (in this case, it would be the generic base class Event, which might even be an abstract base class or an interface, but for the purposes of this example it is enough to have a concrete base class). The method no longer works with specific types of event, but just with generic events that follow a common interface—they are all polymorphic with respect to the meets_condition method.

Notice how events are discovered through the __subclasses__() method. Supporting new types of event is now just about creating a new class for that event that has to inherit from Event and implement its own meets_condition() method, according to its specific business logic.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.124.145