[ Team LiB ] |
Recipe 3.4 Polymorphism via Concrete or Abstract Base ClassesProblemYou need to build several classes that share many common traits. These classes may share common properties, methods, events, delegates, and even indexers; however, the implementation of these may be different for each class. These classes should not only share common code but also be polymorphic in nature. That is to say, code that uses an object of the base class should be able to use an object of any of these classes in the same manner. SolutionUse an abstract base class to create polymorphic code. To demonstrate the creation and use of an abstract base class, here is an example of three classes, each defining a media type: magnetic, optical, and punch card. An abstract base class, Media, is created to define what each derived class will contain: public abstract class Media { public abstract void Init( ); public abstract void WriteTo(string data); public abstract string ReadFrom( ); public abstract void Close( ); private IntPtr mediaHandle = IntPtr.Zero; public IntPtr Handle { get {return(mediaHandle);} } } Next, the three specialized media type classes, which inherit from Media, are defined to override each of the abstract members: public class Magnetic : Media { public override void Init( ) { Console.WriteLine("Magnetic Init"); } public override void WriteTo(string data) { Console.WriteLine("Magnetic Write"); } public override string ReadFrom( ) { Console.WriteLine("Magnetic Read"); string data = ""; return (data); } public override void Close( ) { Console.WriteLine("Magnetic Close"); } } public class Optical : Media { public override void Init( ) { Console.WriteLine("Optical Init"); } public override void WriteTo(string data) { Console.WriteLine("Optical Write"); } public override string ReadFrom( ) { Console.WriteLine("Optical Read"); string data = ""; return (data); } public override void Close( ) { Console.WriteLine("Optical Close"); } } public class PunchCard : Media { public override void Init( ) { Console.WriteLine("PunchCard Init"); } public override void WriteTo(string data) { Console.WriteLine("PunchCard WriteTo"); } public override string ReadFrom( ) { Console.WriteLine("PunchCard ReadFrom"); string data = ""; return (data); } public override void Close( ) { Console.WriteLine("PunchCard Close"); } } The following methods, TestMediaABC and UseMedia, show how any of the three media types can be used polymorphically from within the UseMedia method: public void TestMediaABC( ) { Media x = new Magnetic( ); UseMedia(x); Console.WriteLine( ); x = new Optical( ); UseMedia(x); } private void UseMedia(Media media) { media.Init( ); media.WriteTo("text"); media.ReadFrom( ); Console.WriteLine(media.Handle); media.Close( ); Console.WriteLine(media.ToString( )); } The output of these methods is shown here: Magnetic Init Magnetic Write Magnetic Read 0 Magnetic Close Magnetic Optical Init Optical Write Optical Read 0 Optical Close Optical DiscussionPolymorphism through an abstract base class is a powerful tool. With this tool, you are able to create a method (UseMedia in this solution) that accepts a parameter whose specific type is known only at runtime. Since the use of this parameter is similar for all objects that can be passed in to this method, we do not have to worry about the specific class that is passed in; we need to know only how the abstract base class is defined. It is through this abstract base class definition that we know how to use the specific type. There are several things to keep in mind when using an abstract base class:
It is possible to use interfaces to implement polymorphism; this is discussed at length in Recipe 3.17. There are several advantages to using an abstract base class over an interface:
You should also consider using an abstract base class over an interface when a lot of disparate members need to be overridden in the derived classes. For example, if you are implementing a set of members that control searching or sorting of items, you should initially consider interfaces, since this is a focused set of members that may be implemented over a wide range of unrelated classes. If you were implementing a set of members that determines the base functionality for a complete type, such as the Media type, you would want to use an abstract base class. See Recipe 3.17 for the advantages of using interface polymorphism over abstract base classes. Notice that the abstract Media class in this recipe could be written as a concrete class (i.e., remove the abstract keyword and add implementations to all abstract methods). This would allow you to create objects from the Media class. If you do not wish for objects to be created from your base class (Media), you should make it abstract. See AlsoSee Recipe 3.17; see section 10.1.1.1, "Abstract Classes", in the C# Language Specification. |
[ Team LiB ] |