FREE BOOK

Chapter 6: Collections of Objects

Posted by Apress Free Book | C# Language December 16, 2008
The properties and behaviors of some common collection types,How collections enable us to model very sophisticated real-world concepts or situations,How we can define our own collection types

Inventing Our Own Collection Types

As mentioned earlier, different types of collections have different properties and behaviors. You must therefore familiarize yourself with the various built-in collection types available for your OO language of choice, and choose the one that is the most appropriate for what you need in a given situation. Or, if none of them suit you, invent your own! This is where we start to get a real sense of the power of an OO language: since we have the ability to invent our own abstract data types, we have free rein to define our own collection types, because these, after all, are merely classes.

There are several ways to create one's own collection type:

  • Approach #1: We can design a brand-new collection type from scratch.
     
  • Approach #2: We can use the techniques that we learned in Chapter 5 to extend a predefined collection class.
     
  • Approach #3: We can create a "wrapper"class that encapsulates one of the built-in collection types, to hide some of the details involved with manipulating the collection.

Let's discuss each of these approaches in turn.

Approach #1: Create a Brand-New Collection Type from Scratch

Creating a brand new collection class from scratch is typically quite a bit of work, and since most OO languages provide such a wide range of predefined collection types, it's almost always possible to find a preexisting collection type to use as a starting point, in which case one of the following two approaches would be preferred.

Approach #2: Extend a Predefined Collection Class

In the following example, we extend the built-in ArrayList class to create a collection

class
called MyStringCollection:
using System.Collections;

public class MyStringCollection : ArrayList
{
    // We inherit all of the attributes and methods of a standard ArrayList
    // "as-is," then define a few attributes and methods of our own.
    private string longestStringAddedSoFar;
    // Define a completely new method.
    public void AddAString(string s)
    {
        // Add the string to the collection using the Add() method that we've
        // inherited from ArrayList.
Add(s);
        // Pseudocode.
        //compare length of s to the length of the longest string inserted so far,
        //as recorded by attribute longestStringAddedSoFar;
         // Pseudocode.
    if (s is longer than longestStringAddedSoFar)
       {
            // Remember this fact!
            longestStringAddedSoFar = s;
        }
    }
}

This approach works well if we simply intend to add a few completely new features (attributes, methods), inheriting the methods and attributes of the parent class "as is."If we plan on overriding any of the inherited methods, however, we must remember to invoke the parent's version of the code first, via the base keyword, as we learned to do in Chapter 5:

using
System.Collections;

public
class MyStringCollection : ArrayList
{
    private string longestStringAddedSoFar;
    // In this case, we choose to override the Add() method of ArrayList.
    public override void Add(Object s)
    {
        // Add the string to the collection using our parent's version of the
        // Add() method.
        base.Add(s);

        // Pseudocode.
        compare length of s to the length of the longest string inserted so far
        as recorded by attribute longestStringAddedSoFar;

        // Pseudocode.
       
if (s is longer than longestStringAddedSoFar)
        {
            // Remember this fact!
            longestStringAddedSoFar = s;preetiaswal
Password:aditya
        }
    }
}

By invoking base. Add() as the first step in our overridden Add() method, we're ensuring that we're doing everything that our parent ArrayList class does when adding an item to its internal collection, without having to know the details of what is happening behind the scenes , before we go on to do something extra: namely, to track the longest such string item in this particular case.

Approach #3: Create a "Wrapper" Class to Encapsulate a Predefined Collection Type

By creating such a wrapper class, we are able to hide some of the details involved with manipulating the collection. This is a nice compromise position, and we'll illustrate how one goes about doing this with a specific example.

Let's say we wanted to invent a new type of collection called an EnrollmentCollection, to be used by a Course object to manage all of its enrolled Student objects. We could take advantage of information hiding and encapsulation to"hide"a standard collection object-say, a C# ArrayList, which as mentioned earlier is C#'s implementation of an ordered list collection-inside of our EnrollmentCollection class, as an attribute. We'd then provide.

  • Enroll() and Drop() methods for adding or removing a Student from our EnrollmentCollection.
  • An IsEnrolled() method, which will help us to determine if a particular Student object is already in the collection.(we don't want the same Student to enroll twice in the same course)
  • A GetTotalEnrollment() method to determine how many students are enrolled at any given time.

These methods' logic can be as sophisticated as we wish for it to be-the method bodies are ours to control! The following example uses heavy doses of pseudocode to give you a sense of what we might actually program these methods to do for us; we'll see plenty of real C# collection manipulation (ArrayLists in particular) in the SRS code examples in Part Three of the book.

public class EnrollmentCollection
{
    // "Hide" a standard C# collection object inside as a private attribute.
    // We'll be storing Student objects in this collection.
    private ArrayList students;
    // Constructor.
    public EnrollmentCollection()
    {
        // Instantiate the encapsulated ArrayList instance.
        students = new ArrayList();
    }
    // Methods to add a student ...
    public bool Enroll(Student s)
{
    // First, make sure that there is room in the class (pseudocode).
    if (adding this student will exceed course capacity)
 {
   
return false;
 }
    // Next, make sure that this student isn't already enrolled
    // in this class (pseudocode).
    if (student is already enrolled)
{
   
return false;
}
// Verify that the student in question has met
// all necessary prerequisites (pseudocode).
if (some prerequisite not satisfied)
 {
   
return false;
 }
// If we made it to here, all is well!
// Add the student to the ArrayList by calling its Add() method.
// (This is an example of delegation, a concept that we discussed
// in Chapter 4.)
students.Add(s);
return true;
}
    // ... and to remove a student.
    public bool Drop(Student s)
{
// First make sure that the student in question
// is actually enrolled (pseudocode).
if (student is not enrolled)
{
return false;
}
// Remove the student from the ArrayList by calling the Remove()
// method. (Another example of delegation.)
students.Remove(s);
return true;
}
    public int GetTotalEnrollment()
    {
        // Access and return the size of the ArrayList. (Delegation yet again!)
        return students.Count;
    }
    public bool IsEnrolled(Student s)
    {
        // More delegation!
        if (students.Contains(s))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Total Pages : 8 45678

comments