The difference between a class and an object is a source of confusion for programmers new to the terminology of object-oriented programming. To illustrate the difference between these two terms, let's make our EmployeeApp example more realistic by assuming that we're working not with a single employee but with an entire company of employees.
Using the C language, we could define an array of employees-based on the EMPLOYEE structure-and start from there. Because we don't know how many employees our company might one day employ, we could create this array with a static number of elements, such as 10,000. However, given that our company currently has only Amy as its sole employee, this wouldn't exactly be the most efficient use of resources. Instead, we would normally create a linked list of EMPLOYEE structures and dynamically allocate memory as needed in our new payroll application.
My point is that we're doing exactly what we shouldn't be doing. We're expending mental energy thinking about the language and the machine-in terms of how much memory to allocate and when to allocate it-instead of concentrating on the problem domain. Using objects, we can focus on the business logic instead of the machinery needed to solve the problem.
There are many ways to define a class and distinguish it from an object. You can think of a class as simply a type (just like char, int, or long) that has methods associated with it. An object is an instance of a type or class. However, the definition I like best is that a class is a blueprint for an object. You, as the developer, create this blueprint as an engineer would create the blueprint of a house. Once the blueprint is complete, you have only one blueprint for any given type of house. However, any number of people can purchase the blueprint and have the same house built. By the same token, a class is a blueprint for a given set of functionality, and an object created based on a particular class has all the functionality of the class built right in.
Saturday, January 30, 2010
Instantiation
A term unique to object-oriented programming, instantiation is simply the act of creating an instance of a class. That instance is an object. In the following example, all we're doing is creating a class, or specification, for an object. In other words, no memory has been allocated at this time because we have only the blueprint for an object, not an actual object itself.
Have a look at the following C# code: -
class Employee
{
public Employee(string firstName, string lastName,
int age, double payRate)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.payRate = payRate;
}
protected string firstName;
protected string lastName;
protected int age;
protected double payRate;
public double CalculatePay(int hoursWorked)
{
// Calculate pay here.
return (payRate * (double)hoursWorked);
}
}To instantiate this class and use it, we have to declare an instance of it in a method similar to this: -public static void Main()
{
Employee emp = new Employee ("Amy", "Anderson", 28, 100);
}In this example, emp is declared as type Employee and is instantiated using the new operator. The variable emp represents an instance of the Employee class and is considered an Employee object. After instantiation, we can communicate with this object through its public members. For example, we can call the emp object's CalculatePay method. We can't do this if we don't have an actual object. (There is one exception to this, and that's when we're dealing with static members. I'll discuss static members in both Chapter 5 and Chapter 6, "Methods.") -Have a look at the following C# code: -
public static void Main()
{
Employee emp = new Employee();
Employee emp2 = new Employee();
}Here we have two instances-emp and emp2-of the same Employee class. While programmatically each object has the same capabilities, each instance will contain its own instance data and can be treated separately. By the same token, we can create an entire array or collection of these Employee objects. Chapter 7, "Properties, Arrays, and Indexers," will cover arrays in detail. However, the point I want to make here is that most object-oriented languages support the ability to define an array of objects. This, in turn, gives you the ability to easily group objects and iterate through them by calling methods of the object array or by subscripting the array. Compare this to the work you'd have to do with a linked list, in which case you'd need to manually link each item in the list to the item that comes before and after it.
Labels:
OOPS
Everything Is an Object
In a true object-oriented language, all problem domain entities are expressed through the concept of objects. (Note that in this book I'll be using the Coad/Yourdon definition for "problem domain"-that is, that a problem domain is the problem you're attempting to solve, in terms of its specific complexities, terminology, challenges, and so on.) As you might guess, objects are the central idea behind object-oriented programming. Most of us don't walk around thinking in terms of structures, data packets, function calls, and pointers; instead, we typically think in terms of objects. Let's look at an example.
If you were writing an invoicing application and you needed to tally the detail lines of the invoice, which of the following mental approaches would be more intuitive from the client's perspective? -
Notice that the second approach required an object to perform work on your behalf-that is, to total the detail lines. An object doesn't contain data only, as a structure does. Objects, by definition, comprise data and the methods that work on that data. This means that when working with a problem domain we can do more than design the necessary data structures. We can also look at which methods should be associated with a given object so that the object is a fully encapsulatedbit of functionality. The examples that follow here and in the coming sections help illustrate this concept.
Now let's look at a C# version of this example: -
Now, one valid comment might be that I could have abstracted the C client's code by creating a function to access the EMPLOYEE structure. However, the fact that I'd have to create this function completely apart from the structure being worked on is exactly the problem. When you use an object-oriented language such as C#, an object's data and the methods that operate on that data (its interface) are always together.
Keep in mind that only an object's methods should modify an object's variables. As you can see in the previous example, each Employee member variable is declared with the protected access modifier, except for the actual CalculatePay method, which is defined as public. Access modifiers are used to specify the level of access that derived class and client code has to a given class member. In the case of the protected modifier, a derived class would have access to the member, but client code would not. The public modifier makes the member accessible to both derived classes and client code. I'll go into more detail on access modifiers in Chapter 5, "Classes," but the key thing to remember for now is that modifiers enable you to protect key class members from being used incorrectly.
If you were writing an invoicing application and you needed to tally the detail lines of the invoice, which of the following mental approaches would be more intuitive from the client's perspective? -
- Non-object-oriented approach I'll have access to a data structure representing an invoice header. This invoice header structure will also include a doubly linked list of invoice detail structures, each of which contains a total line amount.Therefore, to get an invoice total, I need to declare a variable named something like totalInvoiceAmount and initialize it to 0, get a pointer to the invoice header structure, get the head of the linked list of detail lines, and then traverse the linked list of detail lines. As I read each detail line structure, I'll get its member variable containing the total for that line and increment my totalInvoiceAmount variable.
- Object-oriented approach I'll have an invoice object, and I'll send a message to that object to ask it for the total amount. I don't need to think about how the information is stored internally in the object, as I had to do with the non-object-oriented data structure. I simply treat the object in a natural manner, making requests to it by sending messages. (The group of messages that an object can process are collectively called the object's interface. In the following paragraph, I'll explain why thinking in terms of interface rather than implementation, as I have done here, is justifiable in the object-oriented approach.)
Notice that the second approach required an object to perform work on your behalf-that is, to total the detail lines. An object doesn't contain data only, as a structure does. Objects, by definition, comprise data and the methods that work on that data. This means that when working with a problem domain we can do more than design the necessary data structures. We can also look at which methods should be associated with a given object so that the object is a fully encapsulatedbit of functionality. The examples that follow here and in the coming sections help illustrate this concept.
NOTE
The code snippets in this chapter present the concepts of object-oriented programming. Keep in mind that while I present many example code snippets in C#, the concepts themselves are generic to OOP and are not specific to any one programming language. For comparison purposes in this chapter, I'll also present examples in C, which is not object-oriented.
Let's say you're writing an application to calculate the pay of your new company's only employee, Amy. Using C, you would code something similar to the following to associate certain data with an employee: -The code snippets in this chapter present the concepts of object-oriented programming. Keep in mind that while I present many example code snippets in C#, the concepts themselves are generic to OOP and are not specific to any one programming language. For comparison purposes in this chapter, I'll also present examples in C, which is not object-oriented.
struct EMPLOYEE
{
char szFirstName[25];
char szLastName[25];
int iAge;
double dPayRate;
};Here's how you'd calculate Amy's pay by using the EMPLOYEE structure: -void main()
{
double dTotalPay;
struct EMPLOYEE* pEmp;
pEmp = (struct EMPLOYEE*)malloc(sizeof(struct EMPLOYEE));
if (pEmp)
{
pEmp->dPayRate = 100;
strcpy(pEmp->szFirstName, "Amy");
strcpy(pEmp->szLastName, "Anderson");
pEmp->iAge = 28;
dTotalPay = pEmp->dPayRate * 40;
printf("Total Payment for %s %s is %0.2f",
pEmp->szFirstName, pEmp->szLastName, dTotalPay);
}
free(pEmp);
}In this example, the code is based on data contained in a structure and some external (to that structure) code that uses that structure. So what's the problem? The main problem is one of abstraction: the user of the EMPLOYEE structure must know far too much about the data needed for an employee. Why? Let's say that at a later date you want to change how Amy's pay rate is calculated. For example, you might want to factor in FICA and other assorted taxes when determining a net payment. Not only would you have to change all client code that uses the EMPLOYEE structure, but you would also need to document-for any future programmers in your company-the fact that a change in usage had occurred.Now let's look at a C# version of this example: -
using System;
class Employee
{
public Employee(string firstName, string lastName,
int age, double payRate)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.payRate = payRate;
}
protected string firstName;
protected string lastName;
protected int age;
protected double payRate;
public double CalculatePay(int hoursWorked)
{
// Calculate pay here.
return (payRate * (double)hoursWorked);
}
}
class EmployeeApp
{
public static void Main()
{
Employee emp = new Employee ("Amy", "Anderson", 28, 100);
Console.WriteLine("\nAmy's pay is $" + emp.CalculatePay(40));
}
}In the C# version of the EmployeeApp example, the object's user can simply call the object's CalculatePay method to have the object calculate its own pay. The advantage of this approach is that the user no longer needs to worry about the internals of exactly how the pay is calculated. If at some time in the future you decide to modify how the pay is calculated, that modification will have no impact on existing code. This level of abstraction is one of the basic benefits of using objects.Now, one valid comment might be that I could have abstracted the C client's code by creating a function to access the EMPLOYEE structure. However, the fact that I'd have to create this function completely apart from the structure being worked on is exactly the problem. When you use an object-oriented language such as C#, an object's data and the methods that operate on that data (its interface) are always together.
Keep in mind that only an object's methods should modify an object's variables. As you can see in the previous example, each Employee member variable is declared with the protected access modifier, except for the actual CalculatePay method, which is defined as public. Access modifiers are used to specify the level of access that derived class and client code has to a given class member. In the case of the protected modifier, a derived class would have access to the member, but client code would not. The public modifier makes the member accessible to both derived classes and client code. I'll go into more detail on access modifiers in Chapter 5, "Classes," but the key thing to remember for now is that modifiers enable you to protect key class members from being used incorrectly.
Labels:
OOPS
Tuesday, January 26, 2010
Allow only numbers/digits in TextBox
<HTML>
<HEAD>
<SCRIPT language=Javascript>
function isNumberKey(evt)
{
var charCode = (evt.which) ? evt.which : event.keyCode
if (charCode > 31 && (charCode <> 57))
return false;
return true;
}