Han Solo was a good guy. He was however unfortunate at times.
Image credit: https://flic.kr/p/h8jDb
Yep, that's right, as you likely know Han Solo was encased, even encapsulated in carbonite by the notorious gangster Jabba the Hut. You see Jabba was taught in space gangster school that in order to keep his system working as designed he needed to encapsulate his system behind a rock solid interface. Through his vast experience collecting debt he had come to know that carbonite fit the bill. However, unfortunately for Jabba, he didn't have a true understanding of encapsulation. He just took the best practices he had gained in school and directly applied them, without grasping the principles. This ultimately led to his downfall at the hands of a rag-tag team of do-gooders at a Sarlacc pit.
The lesson here? Let's understand the principles of encapsulation, not just the tactical best practices and idioms. For example, I remember being taught that we always make properties (or data members, or fields, etc) private and then only operate on them through setter and getter methods. Asking "Why?" makes for a fun discussion. If you have a class with a property, and you want to make access and modification of that property publicly available to anyone using your class, then why not just make the property public?
Think on that for a second. I find that many people never have.
One thought is that assigning a setter facilitates the ability to do error checking on the property. This is true, but incomplete. Even for properties that don't require any validation it is drilled into our heads that we should have the empty-boiler-plate-pass-through setters and getters.
Ok, then why else? I don't deny the need in many languages to have these methods to encapsulate private data. However, for me, the principle at play is that doing so follows the principle behind encapsulation, which is information hiding. In many languages, these boiler plate setters and getters allow the software to separate out its implementation from its interface. This enables the software to evolve from its current implementation to another implementation that fits the needs of future me, which of course I don't know yet (even if someone out there does). If we expose fields or properties in languages like C++ or Java® this flexibility is lost. Yes it is in our interface that we can access and modify a given property, but when we expose the property directly as public this also exposes implementation. Specifically, it exposes a couple things right off the bat:
- The property is actually stored on the object (this object even!) and is in memory.
- The property does not (and cannot ever) be subject to input validation when modified and can never go through preprocessing when accessed.
Even if today there is no input validation, or the property is held in memory on the object, adding these setters and getters is important to allow the flexibility to change our minds in the future. Maybe in the future we refactor and would like to delegate the ownership of the property to another object. Perhaps we would like to calculate the result every time it is accessed. If we have the property encapsulated properly this sort of change is not a problem at all.
So, in MATLAB does it follow that we should make all properties private and write our own getter and setter accessor methods? Absolutely not! In fact, unlike many other languages, properties in MATLAB are already encapsulated. For example, see the following class:
classdef Carbonite properties(SetAccess=private) HanSolo end end
As you can see, the HanSolo property restricts modification, but allows access to the property. That is the only thing in the interface. Note that the following different implementations all still are faithful to that basic interface without the client code ever being the wiser. What is in the interface is the what, what is encapsulated is the how.
Delegation - assign someone else to to the work:
classdef Carbonite % This implementation delegates to some other class. properties(Dependent, SetAccess=private) HanSolo end properties(Access=private) HanSoloAccessor = HanSoloDelegate; end methods function solo = get.HanSolo(carbonite) solo = carbonite.HanSoloAccessor.HanSolo; end end end
Calculation - Don't store anything, recalculate every time:
classdef Carbonite % This implementation creates a new HanSolo every time properties(Dependent, SetAccess=private) HanSolo end methods function solo = get.HanSolo(carbonite) solo = utils.createNewHanSolo; end end end
Preprocessing - Add a bit of flavor in a getter, do some error checking in a setter:
classdef Carbonite % This implementation preprocesses the stored value of HanSolo before % giving it back, this time with his trademark hat from a different set % of movies. If the property was modifiable, you could add a setter to % perform error checking when modifying the value. properties(SetAccess=private) HanSolo end properties(Access=private) IndyHat = IndianaJonesFedora; end methods function solo = get.HanSolo(carbonite) solo = carbonite.HanSolo; solo.add(carbonite.IndyHat); end end end
Ok you get the point. MATLAB's model for properties doesn't break encapsulation, so there is not need for the boiler plate setters and getters. You can expose a property's set and get access to match whether you want it to be accessed or modified at all, and you can do this without exposing the implementation details because you can always add the set.Property or get.Property methods to change the implementation. The implementation is still, say it with me.... encapsulated!
So what was Jabba's mistake? He didn't understand the notion of a leaky abstraction. He still exposed some of his implementation because he was so proud of his HanSolo prize that he showcased Han Solo as his favorite decoration. While Jabba thought he was encapsulated in the carbonite, he didn't leverage encapsulation to achieve information hiding. Everyone knew what was inside that capsule, including a newly minted Jedi and his friends (one of whom was an extremely loyal wookie I might add). If Jabba had hid his prize, or perhaps if his carbonite was a little thicker so nobody could tell the difference between the Han Solo slab and all the other smugglers who were late in their debt payments, perhaps he would still be alive a long time ago in a galaxy far far away.
...or what if he used this implementation?
classdef Carbonite % This implementation clones HanSolo each time as a decoy to pesky Jedi. properties(Dependent, SetAccess=private) HanSolo end properties(Access=private) RealHanSolo end methods function solo = get.HanSolo(carbonite) solo = clone(carbonite.RealHanSolo); end end end
That would have had the nice effect of punishing the real Han Solo while getting his friends off his back.
Takeway, we should understand the principles behind encapsulation, not just the formulas. Let's not be like Jabba, his software wasn't any good anyway.
要发表评论，请点击 此处 登录到您的 MathWorks 帐户或创建一个新帐户。