|only for RuBoard|
1.1 Visual Basic .NET and Object-Oriented Programming
Visual Basic .NET is a fully object-oriented programming language, which means it supports the four basic tenets of object-oriented programming: abstraction, encapsulation, inheritance, and polymorphism.
We have already conceptualized many of these object-oriented concepts by just looking at the objects that surround us in our everyday lives. Let's look more closely at these terms and see what they actually mean and what they do for developers of object-oriented software.
A radio has a tuner, an antenna, a volume control, and an on/off switch. To use it, you don't need to know that the antenna captures radio frequency signals, converts them to electrical signals, and then boosts their strength via a high-frequency amplification circuit. Nor do you need to know how the resulting current is filtered, boosted, and finally converted into sound. You merely turn on the radio, tune in the desired station, and listen. The intrinsic details are invisible. This feature is great because now everyone can use a radio, not just people with technical know-how. Hiring a consultant to come to your home every time you wanted to listen to the radio would become awfully expensive. In other words, you can say that the radio is an object that was designed to hide its complexity.
If you write a piece of software to track payroll information, you would probably want to create an Employee object. People come in all shapes , sizes, and colors. They have different backgrounds, enjoy different hobbies, and have a multitude of beliefs. But perhaps, in terms of the payroll application, an employee is just a name , a rank, and a serial number, while the other qualities are not relevant to the application. Determining what something is, in terms of software, is abstraction .
In object-oriented software, complexity is managed by using abstraction. Abstraction is a process that involves identifying the crucial behavior of an object and eliminating irrelevant and tedious details. A well thought-out abstraction is usually simple, slanted toward the perspective of the user (the developer using your objects), and has probably gone through several iterations. Rarely is the initial attempt at an abstraction the best choice.
Remember that the abstraction process is context sensitive. In an application that will play music, the radio abstraction will be completely different from the radio abstraction in a program designed to teach basic electronics. The internal details of the latter would be much more important than the former.
Programming languages like C and Pascal can both produce object-like constructs. In C, this feature is called a struct ; in Pascal, it is referred to as a record . Both are user-defined data types. In both languages, a function can operate on more than one data type. The inverse is also true: more than one function can operate on a single data type. The data is fully exposed and vulnerable to the whims of anyone who has an instance of the type because these languages do not explicitly tie together data and the functions that operate on that data.
In contrast, object-oriented programming is based on encapsulation . When an object's state and behavior are kept together, they are encapsulated. That is, the data that represents the state of the object and the methods (Functions and Subs) that manipulate that data are stored together as a cohesive unit.
Encapsulation is often referred to as information hiding . But although the two terms are often used interchangeably, information hiding is really the result of encapsulation, not a synonym for it. They are distinct concepts. Encapsulation makes it possible to separate an object's implementation from its behaviorto restrict access to its internal data. This restriction allows certain details of an object's behavior to be hidden. It allows us to create a "black box" and protects an object's internal state from corruption by its clients .
Encapsulation is also frequently confused with abstraction. Though the two concepts are closely related , they represent different ideas. Abstraction is a process. It is the act of identifying the relevant qualities and behaviors an object should possess. Encapsulation is the mechanism by which the abstraction is implemented. It is the result. The radio, for instance, is an object that encapsulates many technologies that might not be understood clearly by most people who benefit from it.
In Visual Basic .NET, the construct used to define an abstraction is called a class . The terms class and object are often used interchangeably, but an object is actually an instance of a class. A component is a collection of one or more object definitions, like a class library in a DLL.
Inheritance is the ability to define a new class that inherits the behaviors (and code) of an existing class. The new class is called a child or derived class , while the original class is often referred to as the parent or base class .
Inheritance is used to express "is-a" or " kind-of " relationships. A car is a vehicle. A boat is a vehicle. A submarine is a vehicle. In OOP, the Vehicle base class would provide the common behaviors of all types of vehicles and perhaps delineate behaviors all vehicles must support. The particular subclasses (i.e., derived classes) of vehicles would implement behaviors specific to that type of vehicle. The main concepts behind inheritance are extensibility and code reuse.
In contrast to inheritance, there is also the notion of a "has-a" relationship. This relationship is created by using composition . Composition, which is sometimes referred to as aggregation, means that one object contains another object, rather than inheriting an object's attributes and behaviors. Naturally, a car has an engine, but it is not a kind of engine.
C++ supports a type of reuse called multiple inheritance . In this scenario, one class inherits from more than one base class. But many C++ programmers will tell you that using multiple inheritance can be tricky. Base classes with identical function names or common base classes can create nightmares for even the most experienced programmers.
VB.NET, like Java, avoids this problem altogether by providing support only for single inheritance. But don't worry, you aren't missing out on anything. Situations that seem ideal for multiple inheritance can usually be solved with composition or by rethinking the design.
When it comes to proper object-oriented design, a deep understanding of inheritance and its effects is crucial. Deriving new classes from existing classes is not always as straightforward as it might initially appear. Is a circle a kind of ellipse? Is a square a kind of rectangle? Mistakes in an inheritance hierarchy can cripple an object model.
Polymorphism refers to the ability to assume different forms. In OOP, it indicates a language's ability to handle objects differently based on their runtime type.
When objects communicate with one another, we say that they send and receive messages. The advantage of polymorphism is that the sender of a message doesn't need to know which class the receiver is a member of. It can be any arbitrary class. The sending object only needs to be aware that the receiving object can perform a particular behavior.
A classic example of polymorphism can be demonstrated with geometric shapes. Suppose we have a Triangle , a Square , and a Circle . Each class is a Shape and each has a method named Draw that is responsible for rendering the Shape to the screen.
With polymorphism, you can write a method that takes a Shape object or an array of Shape objects as a parameter (as opposed to a specific kind of Shape ). We can pass Triangles , Circles , and Squares to these methods without any problems, because referring to a class through its parent is perfectly legal. In this instance, the receiver is only aware that it is getting a Shape that has a method named Draw , but it is ignorant of the specific kind of Shape . If the Shape were a Triangle , then Triangle 's version of Draw would be called. If it were a Square , then Square 's version would be called, and so on.
We can illustrate this concept with a simple example. Suppose we are working on a small graphics package and we need to draw several shapes on the screen at one time. To implement this functionality, we create a class called Scene . Scene has a method named Render that takes an array of Shape objects as a parameter. We can now create an array of different kinds of shapes and pass it to the Render method. Render can iterate through the array and call Draw for each element of the array, and the appropriate version of Draw will be called. Render has no idea what specific kind of Shape it is dealing with.
The big advantage to this implementation of the Scene class and its Render method is that two months from now, when you want to add an Ellipse class to your graphics package, you don't have to touch one line of code in the Scene class. The Render method can draw an Ellipse just like any other Shape because it deals with them generically. In this way, the Shape and Scene classes are loosely coupled , which is something you should strive for in a good object-oriented design.
This type of polymorphism is called parametric polymorphism , or generics . Another type of polymorphism is called overloading . Overloading occurs when an object has two or more behaviors that have the same name. The methods are distinguished only by the messages they receive (that is, by the parameters of the method).
Polymorphism is a very powerful concept that allows the design of amazingly flexible applications. Chapter 4 discusses polymorphism in more depth.
|only for RuBoard|