Identifying Inheritance and Interfaces from CRC Insights

Estimated reading: 8 minutes 7 views

You know you’ve crossed from “just playing with CRC cards” to “actually designing” when you start seeing patterns across multiple classes—not just individual responsibilities, but shared behaviors that feel too similar to be coincidental.

That moment is your cue. It’s when CRC abstraction begins to reveal its true power: the ability to spot repetition not as redundancy, but as a design signal. I’ve seen teams jump straight to UML inheritance without this signal, only to end up with tangled hierarchies that violate the Open/Closed Principle.

This chapter walks through how to detect those signals during CRC sessions and transform them into clean, intentional inheritance and interface structures in your UML class diagrams. You’ll learn when to use abstract classes, when to extract interfaces, and how to validate that your decisions are rooted in behavior—not just naming.

By the end, you’ll be translating CRC insights into well-structured, extensible models that stand the test of time and refactoring.

Spotting the Patterns: When CRC Cards Reveal Abstraction

Abstraction doesn’t appear in a vacuum. It emerges from repeated responsibility patterns across multiple CRC cards.

Ask yourself: Do two or more classes share the same behavior—such as “validate,” “calculate,” or “send notification”—but with different data?

If yes, you’re looking at a classic case for CRC abstraction. This is where the real power of CRC modeling shines: you’re not just listing responsibilities—you’re tracking behavioral intent.

Let me share a real example from a healthcare system I once helped model. We had three classes: Patient, Doctor, and Nurse. Each had a responsibility: “verify identity.” At first glance, it seems trivial. But when we noticed the same logic—matching ID number and date of birth—appeared in all three, the pattern screamed for abstraction.

That’s where we introduced Person as an abstract class, pulling out the shared validation logic into a method verifyIdentity(). The result? Less code duplication, clearer intent, and a foundation for future roles like Admin or Visitor.

Don’t rush to refactor before you’ve seen the pattern across at least three cards. That’s the threshold where abstraction becomes justified.

When to Consider CRC Abstraction

  • You see identical or nearly identical method names across multiple classes.
  • Shared logic in responsibilities involves data validation, formatting, or transformation.
  • Classes are different types of the same conceptual entity (e.g., staff, patient, contractor).
  • One class’s behavior is a generalization of another’s, even if not yet formalized.

These aren’t rules—but red flags that merit deeper investigation.

From CRC Abstraction to UML Interface Design

Not every shared behavior needs a class hierarchy. Sometimes, it’s better to model it as an interface.

When you see multiple classes performing the same action but with different data or in different contexts—yet the core behavior is consistent—it’s a strong candidate for interface extraction.

For example, in a payment processing system, you might have:

  • CreditCard with responsibility: “process payment”
  • BankTransfer with responsibility: “process payment”
  • PayPalAccount with responsibility: “process payment”

These aren’t just similar—they’re functionally equivalent in behavior. The data and flow differ, but the contract—“I can process a payment”—is identical.

This is where UML interface design becomes essential. Create an interface named PaymentProcessor with a single method processPayment(). Then, have each payment method implement it.

Why? Because you’re not trying to share implementation. You’re defining a contract. That makes your system more flexible and testable.

Let’s examine the key differences:

Use Case Choose Abstract Class Choose Interface
Shared implementation and state ✅ Yes ❌ No
Only shared behavior (no shared data) ❌ Avoid ✅ Yes
Multiple inheritance needed ❌ Not supported ✅ Yes (in most languages)
Behavior is variant per implementation ❌ Not ideal ✅ Yes

Remember: interfaces are not just for “what” a class does—they’re for who it can be.

When to Use Interfaces in UML Design

  1. When multiple unrelated classes need to share the same behavior.
  2. When you’re modeling cross-cutting concerns like Serializable, Observable, or Cloneable.
  3. When you want to define a common contract without dictating implementation.
  4. When you anticipate new types of objects that might need to join the behavior later.

Interface design isn’t about saving lines of code. It’s about enabling polymorphism, decoupling, and long-term maintainability.

Building Inheritance Hierarchies in UML Class Diagrams

Inheritance in class diagrams isn’t a magic fix. It’s a tool for expressing specialization and generalization, but only when the relationship is truly hierarchical.

Ask: Is the child class a kind of the parent? That’s the golden rule.

If your CRC card says Motorcycle has responsibility “use engine,” and your Car has the same, but Vehicle is the parent, you’re on the right track.

But if Motorcycle is only “like” a Vehicle in name, and its behavior diverges significantly—say, it lacks doors or seatbelts—you risk creating a brittle hierarchy.

Always validate with the Liskov Substitution Principle (LSP). Can a Car object be substituted wherever a Vehicle is expected, without breaking the program?

Here’s how to evolve a CRC hierarchy into a solid UML structure:

  1. Identify the most general class (e.g., Vehicle).
  2. Group classes that are subtypes (e.g., Car, Truck, Motorcycle).
  3. Extract shared behavior into the parent class.
  4. Make the parent class abstract if it doesn’t represent a concrete instance.
  5. Use inheritance arrows (solid line with triangle) to connect child to parent.

Don’t force inheritance just because classes share a name. Book and LibraryCard may both be in a library system, but one isn’t a kind of the other.

Use abstract classes when:

  • You want to share implementation details across a few related classes.
  • The behavior is specific to a domain or category (e.g., ElectronicDevice).
  • You’re modeling a common state (e.g., hasName, hasId).

Use interfaces when:

  • Behavior is orthogonal to the class’s identity.
  • Multiple unrelated classes need to support the same action.
  • You’re building a pluggable architecture (e.g., strategy pattern).

Deciding Between Inheritance and Interfaces: A Decision Tree

Here’s a simple flow to guide your choices during UML modeling:

  1. Do multiple classes share the same behavior but with different data?
    • Yes → Go to step 2.
    • No → Proceed to step 4.
  2. Do these classes share state or common implementation?
    • Yes → Create an abstract class.
    • No → Create an interface.
  3. Do you need to support multiple inheritance?
    • Yes → Use interface.
    • No → Either is fine, but prefer interface for flexibility.
  4. Is one class a kind of another?
    • Yes → Use inheritance.
    • No → Re-evaluate classification.

Run this on your CRC cards. You’ll be surprised how often the answer becomes clear.

Common Pitfalls: When Inheritance Goes Wrong

I’ve reviewed too many class diagrams where inheritance was used to solve a collaboration problem. It’s tempting—but dangerous.

Here are the top three mistakes:

  • Using inheritance to avoid code duplication: Inheritance shouldn’t be a copy-paste shortcut. If two classes share a method, ask if they should share a class at all—or if an interface and delegation would be better.
  • Making abstract classes too broad: A class with too many responsibilities becomes a “god class.” Strip it down. Focus on a single domain concept.
  • Overusing inheritance for UI components: A Button, Checkbox, and TextField may share “render” or “click” behavior, but they’re not specializations of a single concept. Use an interface like UIComponent instead.

When in doubt, favor composition over inheritance. It’s not a rule—it’s a principle.

Frequently Asked Questions

How do I know if my CRC cards should form an inheritance hierarchy?

If a class is a specialized version of another—like Professor is a Person—and they share core behavior and state, that’s a sign to use inheritance. If not, ask: “Could another class take the same role?” If yes, consider an interface.

Can I use both inheritance and interfaces in the same model?

Absolutely. That’s standard practice. A class can inherit from one abstract class and implement multiple interfaces. For example, Student might extend Person (abstract) and implement Serializable, Enrollable, and HasGrade.

What if the shared behavior is only in the name, not the logic?

Name similarity is not design. If Car and Engine both have “start,” but they’re unrelated, don’t force inheritance. Use an interface like Startable to avoid confusion.

How do I avoid deep inheritance chains?

Keep the hierarchy shallow. Rarely go beyond 3–4 levels. If you find yourself with more, ask: “Is this really a hierarchy, or a collection of roles?” Consider using composition or interface-based delegation.

Should I extract interfaces from CRC cards early or wait until UML modeling?

Wait. Extracting interfaces too early can lead to premature abstraction. Let the CRC collaboration reveal the pattern. Then, during UML modeling, ask: “Does this behavior apply to multiple unrelated classes?” If yes, extract the interface.

What’s the difference between CRC abstraction and UML interface design?

CRC abstraction is a discovery process—identifying shared behavior across cards. UML interface design is the formalization—turning that insight into a contract in your diagram. The former is about seeing the pattern. The latter is about documenting it correctly.

Share this Doc

Identifying Inheritance and Interfaces from CRC Insights

Or copy link

CONTENTS
Scroll to Top