OOP Techniques


Now that you've covered the basics and know what objects are and how they work, you should spend some time looking at some of the other features of objects. In this section, you look at:

  • Interfaces

  • Inheritance

  • Polymorphism

  • Relationships between objects

  • Operator overloading

  • Events

  • Reference versus value types

Interfaces

An interface is a collection of public methods and properties that are grouped together to encapsulate specific functionality. Once an interface has been defined, you can implement it in a class. This means that the class will then support all of the properties and members specified by the interface.

Note that interfaces cannot exist on their own. You can't "instantiate an interface" as you can a class. In addition, interfaces cannot contain any code that implements its members; it just defines the members themselves. The implementation must come from classes that implement the interface.

In the earlier coffee example, you might group together many of the more general-purpose properties and methods into an interface, such as AddSugar(), Milk, Sugar, and Instant. You could call this interface something like IHotDrink (interface names are normally prefixed with a capital I). You could use this interface on other objects, perhaps those of a CupOfTea class. You could therefore treat these objects in a similar way, and they may still have their own individual properties (BeanType for CupOfCoffee and LeafType for CupOfTea, for example).

Interfaces implemented on objects in UML are shown using a lollipop syntax. In Figure 8-6, I've split the members of IHotDrink into a separate box using classlike syntax (unfortunately, the current version of Visio doesn't allow interfaces to possess fields or properties).

image from book
Figure 8-6

A class can support multiple interfaces, and multiple classes can support the same interface. The concept of an interface, therefore, makes life easier for users and other developers. For example, you might have some code that uses an object with a certain interface. Provided that you don't use other properties and methods of this object, it is possible to replace one object with another (code using the IHotDrink interface shown earlier could work with both CupOfCoffee and CupOfTea instances, for example). In addition, the developer of the object itself could supply you with an updated version of an object, and as long as it supports an interface that is already in use it becomes easy to use this new version in your code.

Once an interface is published, that is, it has been made available to other developers or end users, it is good practice not to change it. One way of thinking about this is to imagine the interface as a contract between class creators and class consumers. You are effectively saying "every class that supports Interface X will support these methods and properties." If the interface changed at a later date, perhaps due to an upgrade of the underlying code, this could cause consumers of that interface to run incorrectly, or even fail completely. Instead, you should create a new interface that extends the old one, perhaps including a version number such as IHotDrink2. This has become the standard way of doing things, and you are likely to come across numbered interfaces frequently.

Disposable Objects

One interface of particular interest is IDisposable. An object that supports the IDisposable interface must implement the Dispose() method, that is, they must provide code for this method. This method can be called when an object is no longer needed (just before it goes out of scope, for example) and should be used to free up any critical resources that might otherwise linger until the destructor method is called on garbage collection. This gives you more control over the resources used by your objects.

C# allows you to use a structure that makes excellent use of this method. the using keyword allows you to initialize an object that uses critical resources in a code block, where Dispose() is automatically called at the end of this code block. The usage is:

 <ClassName> <VariableName> = new <ClassName>(); ... Using (<VariableName>) { ... } 

Alternatively, you an instantiate the object <VariableName> as part of the using statement:

 using (<ClassName> <VariableName> = new <ClassName>()) { ... } 

In both cases, the variable <VariableName> will be usable within the using code block and will be disposed of automatically at the end (that is, Dispose() is called when the code block finishes executing).

Inheritance

Inheritance is one of the most important features of OOP. Any class may inherit from another, which means that it will have all the members that the class it inherits from has. In OOP terminology, the class being inherited (also known as derived) from is the parent class (also known as the base class). Note that classes in C# may descend only from a single base class directly, although of course that base class may have a base class of its own, and so on.

Inheritance allows you to extend or create more specific classes from a single, more generic base class. For example, consider a class that represents a farm animal (as used by ace octogenarian developer Old MacDonald in his livestock application). This class might be called Animal and possesses methods such as EatFood() or Breed(). You could create a derived class called Cow, which would support all of these methods, but might also supply its own, such as Moo() and SupplyMilk(). You could also create another derived class, Chicken, with Cluck(), and LayEgg() methods.

In UML you indicate inheritance using arrows, as shown in Figure 8-7.

image from book
Figure 8-7



Beginning Visual C# 2005
Beginning Visual C#supAND#174;/sup 2005
ISBN: B000N7ETVG
EAN: N/A
Year: 2005
Pages: 278

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net