Encapsulate state and expose behavior when writing object-oriented code

A-PIE.

You ever heard of that? For some reason my mouth is watering.

A-PIE is not only a delicious baked dessert with a flaky crust and a warm gooey inside, it’s a little acronym/mnemonic to help remember the four most important principles of object-oriented programming (OOP):

  • Abstraction.
  • Polymorphism.
  • Inheritance.
  • Encapsulation.

Encapsulation is what I want to talk about today. It seems like functional became the new exciting shiny thing and everyone forgot about OOP, even in OOP languages. Let’s reset a little bit. If you write in an OOP language (which is a lot of them!), if OOP principles are baked into the design of your language, then one of the worst things you can do is forget them. That would be like holding a knife by the blade and trying to cut cheese with the handle. You’re gonna get sliced!

Another way to say it is it’s going to be like driving an ’85 Honda Civic down the power line trail when there’s a paved road right next to you. This is a story for another time, but a friend and I attempted this once and let me tell you from experience: it’s not pretty unless you want to see some bent metal…

Sorry! Getting off track here. Let’s get back to encapsulation.

So the concept of “data classes” has become quite vogue these days. Kotlin has direct support for data classes and Scala has case classes. These are JVM languages. Java has no direct equivalent, but it’s interesting to note that both approaches are basically shortcut ways to create the classic JavaBean, which is a fancy word for a bag of data with public accessors and mutators.

C# gets at the same idea with automatic properties. If you look at the documentation for automatic properties, there’s a prime example of the fly in my ointment today. In the example, a Customer class is defined, which is then mutated by code outside the class:

Customer class



// This class is mutable. Its data can be modified from
// outside the class.
class Customer
{
    // Auto-Impl Properties for trivial get and set
    public double TotalPurchases { get; set; }
    public string Name { get; set; }
    public int CustomerID { get; set; }

    // other code elided . . . 
}


Enter fullscreen mode Exit fullscreen mode

Program:



class Program
{
    static void Main()
    {
        // Intialize a new object.
        Customer cust1 = new Customer ( 4987.63, "Northwind",90108 );

        //Modify a property
        cust1.TotalPurchases += 499.99;
    }
}


Enter fullscreen mode Exit fullscreen mode

They even put a comment on there: This class is mutable. Its data can be modified from outside the class.

Shame, shame, shame I know your name C#!!!!!!

This is simple Object-Oriented 101! When the goal is to track total purchases, expose that functionality as public behavior on the Customer class, and encapsulate the data needed to make the behavior possible. The code should look something like:

Customer class



// This class' data cannot be modified from outside the class.
class Customer
{
    private double TotalPurchases;
    private string Name;
    private int CustomerID;

    // other code elided . . . 

    public void AddPurchase( DollarAmount amt ) {
        TotalPurchase += amt;
    }
}


Enter fullscreen mode Exit fullscreen mode

Program:



class Program
{
    static void Main()
    {
        Customer cust1 = new Customer ( 4987.63, "Northwind", 90108 );
        cust1.AddPurchase(499.99);
    }
}


Enter fullscreen mode Exit fullscreen mode

See how the properties of the Customer class are now private, private, private?

That’s right! You should keep your privates private. This is apparently not only a lesson I have to keep teaching my two-year-old, but a relevant and timeless adage for programmers of all ages.

Now, there are all kinds of reasons for keeping your privates private. A big one is that this makes it easier for the program to evolve! It’s very possible that we’ll want to move on from tracking just a DollarAmount to something more in the future. We might perhaps want to store a whole list of transactions instead.

So I don’t know about you, but I’d rather get a sharp poke in the eye than spend my afternoon tracking down all references to TotalPurchases and yanking them out of whatever tangled weeds another programmer lost them in. In a good OO design where we kept TotalPurchases private, it’s a one-and-done change. I would simply update the innards of the Customer class and get all that evolution for free!

Of course, it’s really your choice. No one can tell you how to write your code. If you don’t think you’re going to have trouble with “data classes” separate from “behavior classes” in your application, by all means make a good go at it. But trust me, even if it might be fun one time to see how it feels to stick your finger in a light socket, you’re not gonna want to do it again. If I can help save you the trouble, then I’ll feel like I did my job in writing this article. Best of luck!

原文链接:Encapsulate state and expose behavior when writing object-oriented code

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容