A super class Transaction has two subclasses TransactionA and TransactionB. A Transaction is composed of multiple events that occur in time for a specific key (a file, a person, etc.). Depending on events, some transactions have to be discarded.

A concrete example with a file "key" would look like:

  • TransactionA represents a set of file events whereas the file is being read, let's call it TransactionRead
  • TransactionB is a set of file events for the file being written, calling it TransactionWrite

A same file can be read or write at any given time.

An event list would look like this (very simplified):

  1. Open FileA
  2. Open FileB
  3. Create FileB
  4. Read FileA
  5. Write FileB
  6. EOF FileA
  7. Read FileB
  8. EOF FileB

At step 1 and 2, the transaction is yet to be known, we have needed information (a timestamp, a file name, a username, etc.) but we don't know yet if it's a TransactionRead or TransactionWrite.

My rational would be to create a class Transaction that holds enough services to analyze events and a method who_i_am that returns READ or WRITE if the pattern fits (Ex.: Open -> Read -> EOF for a read transaction), None if no pattern found.

At some point the transaction type will be known and I think it would be a good approach to morph Transaction into a TransactionRead. I'm coding in Python atm, but I've never heard of a concept like this. Is it bad, why? Do languages provide tools for late inheritance?


1 Answer 1


Prefer early composition over late inheritance:

  • The class of an object has to be known at creation, and most languages do not allow to change it later. So, if you create a transaction, it IS a Transaction (inheritance);
  • If the object has to change afterwards, it must be via its state: the transaction may HAVE some properties/behaviors depending on the history of events that affected it (composition);
  • Several known design patterns can help. In your case, I could very well imagine :

    • state pattern: Transaction starts with a TransactionUndetermined state, then gets either a TransactionRead or TransactionWrite state, and then finally a TransactionClosed state, depending on the events encountered. The interface exposed would be the same for all the states, but the behavior could change dynamically.
    • decorator pattern: a TransactionRead and TransactionWrite decorator could enrich the Transaction with additional responsibilities/behaviors/properties. The context that uses the Transaction would then have to use the decorator instead of the original object. All the decorators would implement the same base behavior (e.g. forwarding function calls to the original object), but each decorator can expose its own interface for the added responsibilities.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.