Skip to content

Transaction: Inheritance and Composition

In SØAD Framework, transactions are the primary way to handle web requests. Transactions often share common logic, such as master page layout, user authentication, or retrieving user information. To avoid code duplication and improve maintainability, SØAD supports usage of inheritance and composition in transaction classes.

  • Inheritance: Extending a base transaction class to reuse common behavior.
  • Composition: Incorporating other classes within a transaction class to establish a "has-a" relationship. This approach enables the transaction to delegate specific tasks to helper classes, promoting modularity and encapsulation of related functionality.

Both techniques help keep your code DRY (Don't Repeat Yourself) and maintainable.

Inheritance

Inheritance allows transactions to share and extend common behavior defined in a parent transaction class. This is particularly useful for common actions like authentication, fetching user details, or rendering standard layouts.

Example of Inheritance:

Base Transaction:

base_transaction.py
from utils import render

class BaseTransaction(object):
    def __init__(self):
        # Optional: initialize any common properties or methods
        pass

    def view(self, ctx):
        pass

    def get_user_info(self, ctx):
        request = ctx.getRequest()
        session = request.getSession()
        user_id = session.getAttribute("user_id")
        return user_id

Derived Transaction:

dashboard.py
from default.common.base_transaction import BaseTransaction
from utils import render

class Dashboard(BaseTransaction):
    def __init__(self):
        # Optional: call parent constructor if needed
        super(BaseTransaction, self).__init__()

    def view(self, ctx):
        # Use inherited method to get user ID
        current_logged_in_user = self.get_user_info(ctx)

        ctx.output["user_id"] = current_logged_in_user
        ctx.go_to = render.as_view(ctx, "dashboard")

In this example, Dashboard inherits from BaseTransaction. This setup ensures consistent user context is always passed to the view without redundant code.


Composition

Composition in object-oriented programming represents a "has-a" relationship. Instead of inheriting behavior from a parent class, composition means that a class contains one or more objects from other classes as part of its structure.

In SØAD, this allows a transaction to delegate responsibilities to composed objects. It promotes better separation of concerns and greater flexibility compared to inheritance.

Example of Composition:

User Class:

user_service.py
from models import User

class UserService(object):
    def get_user_profile(user_id):
        # Fetch user profile from the database
        user = User.findById(user_id)
        if not user:
            raise Exception("User not found")
        return user

    def update_user_profile(self, user, data):
        #set user properties from data
        ...
        #other logic to update user profile
        ...
        user.saveIt()

Transaction Class using Composition:

profile.py
from utils import render
from default.service.user_service import UserService

class Profile(Layout):
    def __init__(self):
        self.user_service = UserService()

    def view(self, ctx):
        user_id = ...
        user_profile = self.user_service.get_user_profile(user_id)
        ctx.output["profile"] = user_profile
        ctx.go_to = render.as_view(ctx, "profile")

    def update(self, ctx):
        user_id = ...
        #setup parameters from request
        data = ...
        user_profile = self.user_service.get_user_profile(user_id)
        self.user_service.update_user_profile(user_profile, data)
        ctx.go_to = render.as_view(ctx, "profile")

Here, Profile uses the UserService class to handle all user-related logic. This pattern keeps the transaction focused on request handling and delegates specific functionality to dedicated service classes.


Important Note

While SØAD supports inheritance and composition, it is crucial to use these features judiciously. Over-reliance on shared structures can lead to tightly coupled code, making it difficult to manage and debug transactions.

SØAD promotes a discrete design style where transactions are ideally isolated and self-contained. While inheritance and composition are supported, overusing shared structures may introduce tight coupling, leading to unintended side effects when one transaction changes or fails. By keeping each transaction independent, the application becomes more robust, easier to debug, and safer to maintain in production environments.