easejs

Classical Object-Oriented Framework

Please enable JavaScript to take advantage of the interactive
features of this website. Don't worry - it's all
free software.
You can find the source code to this website via the source code link
above within the 'website' branch.

3.1.1 Discussion

One of the major hurdles ease.js aimed to address (indeed, one of the core
reasons for its creation) was that of encapsulation. JavaScript's prototypal
model provides limited means of encapsulating data. Since functions limit
scope, they may be used to mimic private members; these are often referred
to as privileged members. However, declaring classes in this manner
tends be messy, which has the consequence of increasing maintenance costs
and reducing the benefit of the implementation. ease.js aims to provide an
elegant implementation that is both a pleasure to work with and able to
support protected members.

By default, all members are public. This means that the members can be
accessed and modified from within an instance as well as from outside of it.
Subtypes (classes that inherit from it; see Inheritance) will inherit
public members. Public methods expose an API by which users may use your
class. Public properties, however, should be less common in practice for a
very important reason, which is explored throughout the remainder of this
section.

Following common conventions in modern object-oriented languages, members
with an underscore prefix (e.g. _foo) are implicitly private; this
behavior can be overridden by explicitly specifying an access modifier. This
convention allows for more concise member definitions and is more natural to
those who use JavaScript's native prototype model.

3.1.1.1 Encapsulation

Encapsulation is the act of hiding information within a class or
instance. Classes should be thought of black boxes; we want them to do
their job, but we should not concern ourselves with how they do their
job. Encapsulation takes a great deal of complexity out of an implementation
and allows the developer to focus on accomplishing the task by focusing on
the implementing in terms of the problem domain.

For example - consider a class named Dog which has a method
walk(). To walk a dog, we simply call Dog().walk(). The
walk() method could be doing anything. In the case of a real dog,
perhaps it will send a message to the dog's brain, perform the necessary
processing to determine how that command should be handled and communicate
the result to the limbs. The limbs will communicate back the information
they receive from their nerves, which will be processed by the brain to
determine when they hit the ground, thereby triggering additional actions
and the further movement of the other legs. This could be a terribly
complicated implementation if we had to worry about how all of this was
done.

In addition to the actual walking algorithm, we have the state of each of
the legs - their current position, their velocity, the state of each of the
muscles, etc. This state pertains only to the operations performed by the
dog. Exposing this state to everyone wouldn't be terribly useful. Indeed, if
this information was exposed, it would complicate the implementation. What
if someone decided to alter this state in the middle of a walking operation?
Or what if the developer implementing Dog relied on this state in
order to determine when the leg reached a certain position, but later
versions of Dog decided to alter the algorithm, thereby changing those
properties?

By preventing these details from being exposed, we present the developer
with a very simple interface1. Rather than the developer having to be concerned with moving each of
the dog's legs, all they have to do is understand that the dog is being
walked.

When developing your classes, the following best practices should be kept in
mind:

When attempting to determine the best access modifier (see Access Modifiers) to use for a member, start with the least level of visibility
(private) and work your way up if necessary.

If your member is not private, be sure that you can justify your choice.

If protected - why do subclasses need access to that data? Is there a
better way to accomplish the same task without breaking encapsulation?

If public - is this member necessary to use the class externally? In the
case of a method - does it make sense to be part of a public API? If a
property - why is that data not encapsulated? Should you consider an
accessor method?

Footnotes

[1] One would argue that this isn't
necessary a good thing. What if additional flexibility was needed?
Dog, in the sense of this example, can be thought of as a Facade
(GoF). One could provide more flexibility by composing Dog of, say,
Leg instances, a Brain, etc. However, encapsulation still
remains a factor. Each of those components would encapsulate their own
data.