I'm attempting to develop an open-source Python module for modeling task networks for discrete event simulation. The most fundamental component is the task object, which includes various data such as a distribution of possible task duration times, a release condition (criteria for initiating the task), a beginning effect (statements executed upon initiation of the task), an ending effect (statements executed upon conclusion of the task, such as beginning a different task), and so forth. While each task must include all of the above elements, the logic that they contain is unique to each task instance.
An entire task network could conceivably contain any number of tasks, so I would like to make it as easy as possible to create one. Therefore I was thinking of following an object-oriented paradigm and simply having a task class that users could instantiate, but I'm not sure how to implement the fact that there are different behaviors associated with each task instance. The obvious solution would be to make each task a subclass that overrides the main task class (or possibly just supplies a different class implementation file), but that seems silly because it would result in a ton of pointless singletons.
I also considered wrapping these methods in a dictionary that gets passed to the default constructor, but I don't want the process of defining a task to become unintuitive/require too many steps for the end user. I'm also trying to figure out how this task network data should be stored- raw Python, JSON (but as far as I'm aware this just runs into the same problem since JSON cannot represent the behavior associated with a task)? I'm sure this is probably a lot simpler than I'm making it out to be, but can anybody point me toward a good design pattern for this kind of situation? Thanks.