Encapsulation is one of
the most important aspects of object-oriented languages. The rule of
encapsulation is one of keeping things private or masked inside the
domain of an
object, package,
namespace, class, or interface and allowing only expected access to
pieces of functionality. We use the rule of encapsulation in almost
every aspect of OOP
(object-oriented
programming). This rule allows us to build programs like facades,
proxies, bridges, and adapters. It allows us to hide with an
interface or class structure some
functionality that we do
not wish to be publicly or globally known. It allows us to define
scope inside our programs, and helps us to define and group modules
of logic. It provides
ways to allow objects to
communicate without that communication getting either too complex or
too entangled. It provides rules of engagement between different code
bases, and helps us decide what functionality can be known and what
needs to be hidden. Think of encapsulation like your mortgage
company. You send off your mortgage payment every month and get
a statement back showing your loan data. How your payment is applied
and handled inside the mortgage company’s accounting department is
unknown to you, but you can see evidence of it in your statements
and the slowly reducing loan debt against your house. The accounting
processes behind how this process works is invisible to you. It
exists behind the business facade of the mortgage company. The
company has processes and rules based on laws and business practices
to guarantee that your money is safely deposited and applied to
your loan. You know it works; you just don’t know or even care how
it works, as long as it works as expected and returns the expected
results.
Working with
encapsulation within your programs is very similar to the example we
just read. Let’s say we want to build a class that applies your
mortgage payment to your loan. We obviously want to allow limited
access to this class, since it handles money and sensitive
information, so allowing every process around it to access every
method inside it would not be a good idea. So instead we choose two
methods to make public and mark the access of the remaining methods
private. One of the public methods is a method to apply the
payments, including the money and account number as input parameters
and outputting the loan amount left after the payment is applied. The
other is a method to return amortized data surrounding the payment
plan.
class CustomerPayment
{
public double
PostPayment(int loanId, double payment)
{
.....performs post of
payment to customer account
}
public ArrayList
GetAmortizedSchedule(int loanId)
{
...returns an
amortization schedule in array
}
}
Notice that the two
methods in the code above are visible as public. We can assume that
the CustomerPayment class has many other methods and code to help
perform some of the functions of its two public methods, but since we
cannot access them outside the class code they are in effect
invisible to any other classes in the code domain.
This gives us proper
encapsulation of the class methods, allowing only the required
methods to be accessed. Thus, the method of encapsulation for this
class is to allow only the two methods, PostPayment() and
GetAmortizedSchedule(), to be accessed outside the class.
Polymorphism is another
important aspect of objectoriented programming. The rule of
polymorphism states that classes can be altered according to their
state, in effect
making them a different
object based on values of attributes, type, or function. We use
polymorphism in almost every coding situation, especially patterns.
This rule gives us the power to use abstraction and inheritance,
allowing inherited members to change according to how they implement
their base class. It also allows us to change a class’s
purpose and function based
on its current state.
Polymorphism helps
interfaces change their implementation class type simply by allowing
several different classes to use the same interface. Polymorphic
declarations of specific implementations of classes with a common
base or interface are extremely common in object-oriented code. To
better understand polymorphism we can think of an example of using
an interface and a group of classes that implement the interface to
perform different functionality for different implementations.
An interface is a type of
code that is not a class, but acts together with different classes to
define a common link, which would not be possible otherwise. It is
simply a protocol in object-oriented languages that exists between
classes and objects to provide an agreed upon linkage.
Let’s take a look at an
example that illustrates the role polymorphism plays in a
relationship between classes without a common base class and an
interface designed to allow some
common definitions between
these classes. We start out with some common if...then...else code as
we might see in any language, either scripting or object. Our mission
is to use the aspect of polymorphism to make this code more
flexible.
if(IsAntiqueAuto)
AntiqueAuto auto = new
AntiqueAuto();
int cylinders =
auto.Cylinders();
int numDoors =
auto.NumberDoors();
int year =
auto.Year();
string make =
auto.Make();
string model =
auto.Model();
}
The first thing you need
to answer is why do we want to change this code? The answer might be
one of portability: You wish to have many car types and pass the
logic of creating them via the class itself, rather than via a
logical Boolean statement. Or you might wish to make sure all auto
classes have the same methods so your code accessing the object
always knows what to expect. In the code example below we can see an
interface, IAuto, and below it some classes that we have modified to
implement this interface. We can assume that each class also
implements the interface’s methods, each functioning in its own
way, returning values according to the logic specific to the
implemented methods on each class.
public interface IAuto
{
int Cylinders();
int NumberDoors();
int Year();
string Make();
string Model();
}
class AntiqueAuto :
IAuto....
class SportsCar :
IAuto....
class Sedan : IAuto.....
class SUV : IAuto.....
To understand how
polymorphism acts in the interface-class relationship, let’s look
at some code where different class types are created via the IAuto
interface. First, we see how
one of the classes that
implement the interface methods can use the interface to define each
class’s methods as independent logic. Let’s look at an example of
one of the classes
we saw in the previous
code example. Notice that each of the methods that are present in the
interface are represented in the AntiqueAuto implementation and
return values specific to its type of auto. This is mandated by the
compiler, to ensure all methods in the interface are implemented in
the class to determine common functionality between this class and
others that implement the IAuto interface. This defines one aspect of
polymorphism, in that by changing its underlying class type, the
interface can allow different functionality from each class
implementation.
class AntiqueAuto : IAuto
{
public int Cylinders()
{
return 4;
}
public int
NumberDoors()
{
return 3;
}
public int Year()
{
return 1905;
}
public string Make()
{
return "Ford";
}
public string Model()
{
return "Model
T";
}
}
Now, when looking at
another class that implements the same interface, we see it has a
completely different implementation of each of the interface methods:
//another implementation
of IAuto
class SportsCar : IAuto
{
public int Cylinders()
{
return 8;
}
public int
NumberDoors()
{
return 2;
}
public int Year()
{
return 2005;
}
public string Make()
{
return "Porsche";
}
public string Model()
{
return "Boxter";
}
}
Next, we instantiate the
AntiqueAuto class as an instance of the IAuto interface and call each
of the interface methods. Each method returns a value from the
methods implemented on the AntiqueAuto class.
IAuto auto = new
AntiqueAuto();
int cylinders =
auto.Cylinders();
int numDoors =
auto.NumberDoors();
int year = auto.Year();
string make = auto.Make();
string model =
auto.Model();
If we changed the
implemented class to SportsCar or another auto type, the methods
would return different values. This is how polymorphism comes into
play in class relationships. By changing the class type for a common
interface or abstraction, we can change the functionality and scope
of the code without having to code if... then...else statements to
accomplish the same thing.
IAuto auto = new
SportsCar();
int cylinders =
auto.Cylinders();
int numDoors =
auto.NumberDoors();
int year = auto.Year();
string make = auto.Make();
string model =
auto.Model();