Review this design. Should I use composition instead of a large class?

← Getting Started · Ref: Q1027

Yes, this class is doing too much. It handles both user validation and notification — two separate concerns.

Split it into:
- A UserValidator class that checks names and emails
- A Notifier class that sends messages
- The main class delegates to both via composition

Benefits of composition:
- Each class has one responsibility
- You can test validation without notification
- You can swap notification implementations
- EK9 types are closed by default, so composition is the standard extension pattern

Keep each class focused on one concern. Compose them together in a coordinator class.

Example

defines module qa.gettingstarted.compositionreview

  defines class

    UserValidator
      isValidName() as pure
        -> name as String
        <- rtn as Boolean: name.length() > 0

      isValidEmail() as pure
        -> email as String
        <- rtn as Boolean: email.contains("@")

      override operator ? as pure
        <- rtn as Boolean: true

      operator $ as pure
        <- rtn as String: "UserValidator"

    Notifier
      sendWelcome()
        -> name as String
        <- rtn as String: `Welcome ${name}`

      override operator ? as pure
        <- rtn as Boolean: true

      operator $ as pure
        <- rtn as String: "Notifier"

  defines program

    CompositionDemo()
      stdout <- Stdout()

      validator <- UserValidator()
      notifier <- Notifier()

      userName <- "Alice"
      email <- "alice@example.com"

      if validator.isValidName(userName) and validator.isValidEmail(email)
        message <- notifier.sendWelcome(userName)
        stdout.println(message)

Common mistakes

E05030 — EK9 types are closed by default and cannot be extended; 'extends UserValidator' fails with E05030 - use composition instead. See ek9 -h E05030 for details.

Incorrect:

    Notifier extends UserValidator
      sendWelcome()

Correct:

    Notifier
      sendWelcome()
Other ways to ask this
  • Is this class doing too many things?
  • Should I break this class into smaller pieces?
  • Assess whether this class follows single responsibility

Coming from another language?

EK9 types are closed by default. Composition is the primary way to combine behavior from multiple sources.

Keywords: responsibility, review, design, composition, split