DevLearningTools

MODULE 7 · LESSON 09

Encapsulation

Encapsulation as a design principle in ColdFusion — hiding internal state behind controlled access, enforcing invariants in custom setters, and the getMemento() pattern for exposing a snapshot of an object's data.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

The previous two lessons covered the mechanics — variables vs this, access modifiers. Encapsulation is the design principle those mechanics exist to support: keep an object's internal state private, and only allow it to be read or changed through methods that can validate, format, or otherwise control what happens.

Learning Objectives

After completing this lesson, you'll be able to:

  • Explain encapsulation as "controlled access," not just "hiding for its own sake."
  • Write a custom setter that enforces a validation rule the raw property can't enforce on its own.
  • Use the getMemento() pattern to expose a read-only snapshot of an object's data.

Why Hide Data At All?

If every property were freely settable from outside, nothing could stop invalid data from getting in — a negative age, an empty required name, a discount percentage over 100%. Encapsulation means the object itself is responsible for staying valid, by only allowing changes through methods it controls.

A Custom Setter That Enforces a Rule

CFScript — Product.cfc
component {

    variables.price = 0;

    function setPrice(required numeric price) {
        if (arguments.price < 0) {
            throw(message = "Price cannot be negative");
        }
        variables.price = arguments.price;
    }

    function getPrice() {
        return variables.price;
    }

}
Tag Syntax
<cfcomponent>

    <cfset variables.price = 0>

    <cffunction name="setPrice" returnType="void">
        <cfargument name="price" type="numeric" required="true">
        <cfif arguments.price LT 0>
            <cfthrow message="Price cannot be negative">
        </cfif>
        <cfset variables.price = arguments.price>
    </cffunction>

    <cffunction name="getPrice" returnType="numeric">
        <cfreturn variables.price>
    </cffunction>

</cfcomponent>
NOTE

This is why a custom setter (instead of relying purely on accessors="true") matters — the auto-generated setter has no way to know a negative price should be rejected.

Exposing a Snapshot: getMemento()

A common CFML pattern for handing back an object's data — for serializing to JSON, or displaying in a template — without exposing the live object itself is a getMemento() method that returns a plain struct.

CFScript
Simulated output — illustrative only, not a live ColdFusion/Lucee server.
Tag Syntax
Simulated output — illustrative only, not a live ColdFusion/Lucee server.
NOTE

Because getMemento() returns a plain struct (a copy), changing the returned struct afterward has no effect on the object's real internal state.

Common Beginner Mistakes

Relying only on accessors="true" when a property needs validation

The auto-generated setter just assigns the value with no checks. Write a custom setter (and turn off accessors for that specific property, or simply don't declare it as a property) whenever a rule needs enforcing.

Returning a reference to internal mutable data instead of a copy

If getMemento() (or any getter) returns a struct/array that's the actual internal data rather than a copy, code outside the object can mutate it directly — undermining the whole point of encapsulation.

Best Practices

  • Write a custom setter (instead of relying on accessors) for any property that has a validation rule attached to it.
  • Use getMemento() when handing an object's data to something outside the OOP layer — a JSON API response, a template — rather than passing the live object around.

Interview Questions

What's the actual purpose of encapsulation, beyond just "hiding data"?

Controlled access — making sure an object can only be changed through methods that can validate, format, or otherwise enforce that the object stays in a valid state.

What does a getMemento() method typically return?

A plain struct that's a snapshot/copy of the object's data, safe to hand outside the OOP layer without exposing the live object or letting it be mutated indirectly.

Summary

In this lesson, you covered encapsulation as controlled access — validating data in a custom setter, and exposing a safe snapshot of an object's state with getMemento().

What's Next?

The next lesson covers inheritance — extending a component to reuse and build on another component's behavior.