Access modifiers have long been seen as essential to safe and clean code. But they’re ultimately a low-level mechanism for expressing high-level ideas.Access modifiers have long been seen as essential to safe and clean code. But they’re ultimately a low-level mechanism for expressing high-level ideas.

Rethinking Encapsulation: From Private to Public by Design

2025/10/16 13:15
6 min read
For feedback or concerns regarding this content, please contact us at [email protected]

This article is part of a broader discussion in my book Safe by Design: Explorations in Software Architecture and Expressiveness. If you like it, you might enjoy the full read for free on GitHub.

Introduction: Rethinking Access Control

Encapsulation is one of the core pillars of object-oriented programming. It is commonly introduced through the use of access modifiers — private, protected, public, and so on — which restrict visibility of internal implementation details. Most popular object-oriented languages provide access modifiers as the default tool for enforcing encapsulation.

While this approach is effective, it tends to obscure a deeper and arguably more powerful mechanism: the use of explicit interfaces or protocols. Instead of relying on visibility constraints embedded in the language syntax, we can define behavioral contracts directly and intentionally — and often with greater precision and flexibility.

This article offers an alternative perspective on access control, suggesting that access modifiers are, in many cases, just a shorthand for declaring implicit interfaces. We’ll explore how switching from implicit to explicit contracts can improve modularity, enhance design clarity, and even allow us to imagine programming languages that work without private or protected at all.

Access Modifiers as Implicit Interfaces

Access modifiers give us fine-grained control over which parts of a class are visible to the outside world. A private method is hidden from everyone except the class itself. A protected method is visible to subclasses. Package-private (in languages like Java) further narrows or expands visibility based on the module boundary. These modifiers form a visibility matrix, controlling how internal details are exposed.

But here’s the key observation: each combination of access levels effectively defines a contract — a set of methods that a particular group of clients is allowed to use. This is conceptually identical to an interface.

For example, when a class exposes one method as public and keeps the rest private, it’s silently declaring, “This is the only thing you’re allowed to call.” The contract is there — it’s just invisible.

Access modifiers are, in this sense, a mechanism for declaring implicit interfaces. The problem is that they are invisible to tooling and to readers. They offer no way to reason about multiple views of the same object — something explicit interfaces handle much better.

The Power of Explicit Interfaces

Interfaces (or protocols, depending on the language) let us define clearly what capabilities an object exposes — and to whom. Instead of burying access control inside the implementation using private or protected, we can expose different behaviors through multiple public interfaces. This makes the contract visible, composable, and testable.

Interfaces offer several advantages:

  • Clarity: Clients only see the functionality they are supposed to use. No hidden methods leaking through reflection or subclassing.
  • Flexibility: Different clients can interact with the same object through different interfaces, depending on context.
  • Polymorphism: Explicit interfaces enable runtime substitution, mocking, and dependency inversion — all core ideas in modern software design.
  • Encapsulation without obscurity: By expressing visibility through interfaces rather than modifiers, we separate what is exposed from how it’s implemented.

In effect, interfaces give us a more declarative, higher-level alternative to access modifiers. And unlike modifiers, interfaces scale well in large codebases, across modules, teams, and versions.

📘 If you’re enjoying this so far, there’s a lot more in the book — same tone, just deeper. It’s right here if you want to peek.

A Concrete Example

Let’s take a simple class that uses traditional access modifiers to hide internal details:

public class ConsistentObject {     public void methodA() { /* ... */ }     protected void methodB() { /* ... */ }     void methodC() { /* ... */ } // package-private     private void methodD() { /* ... */ } } 

This class defines different visibility levels using Java’s modifiers. But what if we rewrote the same intent using interfaces?

public interface IPublicConsistentObject {     void methodA(); } public interface IProtectedConsistentObject extends IPublicConsistentObject {     void methodB(); } public interface IDefaultConsistentObject extends IProtectedConsistentObject {     void methodC(); } class ConsistentObject implements IDefaultConsistentObject {     public void methodA() { /* ... */ }     public void methodB() { /* ... */ }     public void methodC() { /* ... */ }     public void methodD() { /* ... */ } } 

Here, each interface builds on the previous one, modeling increasingly privileged access. The important difference is that now the contracts are explicit and reusable. Instead of relying on compiler-enforced visibility, we guide client interaction by choosing which interface to provide.

A consumer of this class might only receive a reference of type IPublicConsistentObject, and therefore would only see methodA() — even though the underlying object knows how to do more.

This model makes dependencies more honest and design more modular.

The Limitation: Constructors and Instantiation

There’s one area where access modifiers still feel necessary: controlling object creation.

Constructors can’t be abstracted as easily as methods. You can’t define a constructor in an interface, and you can’t delegate instantiation to a consumer the same way you do method calls. That’s why private constructors (and protected ones, in some cases) remain common — especially when enforcing factory patterns, singletons, or internal lifecycle rules.

But even this limitation is manageable.

If we embrace factory functions or dependency injection, we decouple creation from usage:

interface PublicAPI {     fun doStuff() } private class InternalImplementation : PublicAPI {     override fun doStuff() { /* ... */ } } fun createInstance(): PublicAPI {     return InternalImplementation() } 

In this model, the internal class remains private, and the only way to obtain it is through the createInstance() factory. Clients never need to know — or care — how it was constructed.

This approach makes the object lifecycle part of the module’s explicit API. It also aligns naturally with principles like Inversion of Control, and is widely used in dependency-injection frameworks.

In short, we don’t need private constructors. We just need to move the responsibility of creation one level higher.

Conclusion: In Defense of Public Everything

Access modifiers have long been seen as essential to safe and clean code. But they’re ultimately a low-level mechanism for expressing high-level ideas — contracts, roles, and boundaries.

By shifting from implicit contracts enforced through visibility, to explicit contracts expressed via interfaces and factory functions, we unlock several benefits:

  • Clearer APIs
  • Greater flexibility across modules
  • Better separation of concerns
  • Easier testing, mocking, and substitution

This doesn’t mean private and protected are inherently bad. But they’re a shortcut — a legacy of language design choices made before interface-based composition became mainstream.

We can imagine a language that omits access modifiers entirely and instead relies on structured APIs to express visibility. In that world, encapsulation would still be possible — arguably even more robust — because everything would be explicit, composable, and visible by design.

And maybe that’s a world worth building toward.

If you enjoyed this article, you might like my book Safe by Design: Explorations in Software Architecture and Expressiveness. It dives deeper into topics like this one — contracts, type safety, architectural clarity, and the philosophy behind better code.

👉 Check it out on GitHub

Market Opportunity
PUBLIC Logo
PUBLIC Price(PUBLIC)
$0.01543
$0.01543$0.01543
-0.25%
USD
PUBLIC (PUBLIC) Live Price Chart
Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact [email protected] for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.
Tags:

You May Also Like

CEO Sandeep Nailwal Shared Highlights About RWA on Polygon

CEO Sandeep Nailwal Shared Highlights About RWA on Polygon

The post CEO Sandeep Nailwal Shared Highlights About RWA on Polygon appeared on BitcoinEthereumNews.com. Polygon CEO Sandeep Nailwal highlighted Polygon’s lead in global bonds, Spiko US T-Bill, and Spiko Euro T-Bill. Polygon published an X post to share that its roadmap to GigaGas was still scaling. Sentiments around POL price were last seen to be bearish. Polygon CEO Sandeep Nailwal shared key pointers from the Dune and RWA.xyz report. These pertain to highlights about RWA on Polygon. Simultaneously, Polygon underlined its roadmap towards GigaGas. Sentiments around POL price were last seen fumbling under bearish emotions. Polygon CEO Sandeep Nailwal on Polygon RWA CEO Sandeep Nailwal highlighted three key points from the Dune and RWA.xyz report. The Chief Executive of Polygon maintained that Polygon PoS was hosting RWA TVL worth $1.13 billion across 269 assets plus 2,900 holders. Nailwal confirmed from the report that RWA was happening on Polygon. The Dune and https://t.co/W6WSFlHoQF report on RWA is out and it shows that RWA is happening on Polygon. Here are a few highlights: – Leading in Global Bonds: Polygon holds 62% share of tokenized global bonds (driven by Spiko’s euro MMF and Cashlink euro issues) – Spiko U.S.… — Sandeep | CEO, Polygon Foundation (※,※) (@sandeepnailwal) September 17, 2025 The X post published by Polygon CEO Sandeep Nailwal underlined that the ecosystem was leading in global bonds by holding a 62% share of tokenized global bonds. He further highlighted that Polygon was leading with Spiko US T-Bill at approximately 29% share of TVL along with Ethereum, adding that the ecosystem had more than 50% share in the number of holders. Finally, Sandeep highlighted from the report that there was a strong adoption for Spiko Euro T-Bill with 38% share of TVL. He added that 68% of returns were on Polygon across all the chains. Polygon Roadmap to GigaGas In a different update from Polygon, the community…
Share
BitcoinEthereumNews2025/09/18 01:10
USD/CAD Consolidation Holds with Firm Support – Scotiabank’s Crucial Analysis

USD/CAD Consolidation Holds with Firm Support – Scotiabank’s Crucial Analysis

BitcoinWorld USD/CAD Consolidation Holds with Firm Support – Scotiabank’s Crucial Analysis The USD/CAD currency pair continues to exhibit a phase of consolidation
Share
bitcoinworld2026/03/11 01:55
US Dollar Index Plummets from Iran War Highs as Safe-Haven Frenzy Cools

US Dollar Index Plummets from Iran War Highs as Safe-Haven Frenzy Cools

BitcoinWorld US Dollar Index Plummets from Iran War Highs as Safe-Haven Frenzy Cools NEW YORK, March 2025 – The US Dollar Index (DXY) has retreated sharply from
Share
bitcoinworld2026/03/11 02:25