Composition Over Inheritance

Composition Over Inheritance: एक Class के Object को दूसरी Class में Member की तरह रखना या Define करना, Composition कहलाता है। हमने Composition को इसी अध्‍याय में कई बार Describe किया है। चलिए, उसी Description के आधार पर हम निम्नानुसार एक TTime Object को एक Train Class में एक Data Member की तरह Place करके Composition को Practically समझने की कोशिश करते हैं।

हमने अभी तक TTime Class के कई उदाहरण देखे हैं जिसमें hours व minutes के अनुसार Time को Represent किया गया है। अब मानलो कि हम विभिन्न Trains की Scheduling के लिए एक Program Develop करना चाहते हैं और हम ऐसे Objects के साथ काम करना चाहते हैं जो Trains को Represent कर रहे हैं। सरलता के लिए हमने Train Class में केवल तीन Data Items को ही Include किया है। ये तीन Data Items निम्नानुसार हैं:

trainNumber
departureTime
arrivalTime

हम इसमें और भी Data Include कर सकते हैं जैसे कि Train का नाम, Train किस शहर से रवाना हुई है और Train का अन्तिम Station कौनसा है, आदि। लेकिन हम इन सब को यहां Use नहीं कर रहे हैं। इस Class के Member Functions User से इन Data Items का मान प्राप्त करेंगे और उन्हें Screen पर Display करेंगे। Program निम्नानुसार है:

	// Demonstrates composition: TTime objects in Train class
	#include <iostream.h>
	#include <conio.h>

	class TTime
	{
		private:
			int hours;              	// 0 to 23
			int minutes;            	// 0 to 59

		public:
			// no-arg constructor
			TTime() : hours(0), minutes(0)
			{  }

			// two-arg constructor
			TTime(int h, int m) : hours(h), minutes(m)
			{  }

			void display() const    	// output to screen
			{
				cout << hours << ':' << minutes;
			}

			void get()             	 // input from user
			{
				char dummy;
				cout << "\n   Enter time (format 12:59): ";
				cin >> hours >> dummy >> minutes;
			}
	};  // end class TTime

	class Train
	{
		private:
			long trainNumber;     	// Train Number
			TTime departureTime;  	// TTime
			TTime arrivalTime;    	// objects
		public:
			Train() : trainNumber(0)   	// no-arg constructor
			{  }

			void get()              	// input from user
			{
				char dummy;
				cout << "\nEnter Train number: ";
				cin >> trainNumber;
				cout << "   Departure";
				departureTime.get();
				cout << "   Arrival";
				arrivalTime.get();
			}

			void display() const    	// output to screen
			{
				cout << "Train Number = " << trainNumber;
				cout << "\n   Departure = ";
				departureTime.display();
				cout << "\n   Arrival = ";
				arrivalTime.display();
			}
	};  // end class Train

	void main()
	{
		Train trainArray[100];     	// array holds 100 Train objects
		int total = 0;             	// number of Trains in array
		char ch;                   	// for 'y' or 'n'
		do                         	// get data for Trains
		{
			trainArray[total++].get();
			cout << "Enter another Train (y/n)? ";
			cin >> ch;
		}
		while(ch != 'n');

		for(int j=0; j<total; j++) 	// display data for Trains
		{
			cout << endl;
			trainArray[j].display();
		}
		getch();
	}

Main() Function User को Data Enter करने के लिए Prompt करता है। User जो Data Input करता है, Program उन Data को Train Objects के एक Array में Store करता है और सभी Trains के Data को Output में Display करता है। ये Program User से निम्नानुसार Interaction करता है:

Enter Train number: 1200
   Departure
   Enter time (format 12:59): 10:21
   Arrival
   Enter time (format 12:59): 23:25
Enter another Train (y/n)? y

Enter Train number: 4530
   Departure
   Enter time (format 12:59): 2:10
   Arrival
   Enter time (format 12:59): 15:20
Enter another Train (y/n)? y

Enter Train number: 5610
   Departure
   Enter time (format 12:59): 6:21
   Arrival
   Enter time (format 12:59): 24:00
Enter another Train (y/n)? n

Train Number = 1200
   Departure = 10:21
   Arrival = 23:25

Train Number = 4530
   Departure = 2:10
   Arrival = 15:20

Train Number = 5610
   Departure = 6:21
   Arrival = 24:0

इस Program की train Class को देखें। इसमें TTime Class के Objects को उतने ही सामान्‍य तरीके से Include किया गया है, जिस तरह से हम किसी Integer या float प्रकार के Variable को Data Member के रूप में Class में Include करते हैं।  चलिए, इसी Concept के आधार पर हम फिर से safeArray Class को देखते हैं।

जैसाकि हम जानते हैं, इस Class में एक Array है और एक Overloaded Subscript Operator है जो ये Check करता है कि Class ने जो Index Value Supply की है वह Array की Bound के अन्दर है या नहीं। हम इस safeArray Object को Stack Class में Compose कर रहे हैं। ये Program इसी Chapter में Develop किया गया है।

पिछले उदाहरण में Stack Class में Data को Store करने के लिए एक साधारण Array का प्रयोग किया गया था। लेकिन यदि हम इसमें safeArray Object का प्रयोग करते हैं, तो हमें Stack Class में एक Error Checking Benefit भी प्राप्त हो जाएगा। इस स्थिति में ये पूरी तरह से स्पष्‍ट नहीं है कि Composition Concept का प्रयोग करते हुए Stack Class में safeArray के एक Object को एक Data Member के रूप में Include किया जाए या फिर safeArray Class को Inherit किया जाए।

Composition एक ज्यादा उचित तरीका हो सकता है। क्योंकि safeArray को Stack Class में एक Internal Working करने के लिए Use किया जा रहा है।  इस स्थिति में ये Object Class User से पूरी तरह Hidden रहेगा और Class User के पास ये मानने का कोई कारण नहीं होगा कि Stack एक प्रकार का safeArray है। ये Modified Program निम्नानुसार है:

// creates stack using safe array object as a member of Stack
#include <iostream.h>
#include <process.h>                	// for exit()
#include <conio.h>
class safeArray
{
	private:
		enum {SIZE=100};              	// array size
		int arr[SIZE];                	// ordinary array
	public:
		int& operator [](int n);      	// function declaration
};

int& safeArray::operator [](int n)   	// overloaded []
{                                	// returns by reference
	if( n< 0 || n>=SIZE )
	{ 
		cout << "\nIndex out of bounds"; exit(1); 
	}
	return arr[n];
}

class Stack                        	// stack stores ints in safe array
{
	private:
		safeArray st;                  	// safe array object
		int top;                      	// index of last item pushed

	public:
		Stack()                       	// no-arg constructor
			{ top = -1; }

		void push(int var)            	// place an item on the stack
			{ st[++top] = var; }

		int pop()                     	// remove an item from the stack
			{ return st[top--]; }
};

void main()
{
	Stack s;                         	// create a Stack object
	s.push(11);                      	// push 3 items onto stack
	s.push(12);
	s.push(13);
	cout << s.pop() << endl;  	// pop items and display them
	cout << s.pop() << endl;
	cout << s.pop() << endl;
	cout << s.pop() << endl;  	// woops, popped one too many
	getch();
}

ये Program और इसकी Stack Class दोनों उसी प्रकार से काम कर रहे हैं जिस प्रकार से पहले कर रहे थे] लेकिन इस बार Stack Class में Bound Checking के Statements नहीं लिखे गए हैं, बल्कि इन Bounds Checking Codes को safeArray Class के Object से प्राप्त कर लिया गया है। इस Program का Output निम्नानुसार प्राप्त होता है:

13
12
11
Index out of bounds

Stack में safeArray Object को जब top Variable का गलत मान प्राप्त होता है, तब Compiler Complain करता है। हालांकि हम safeArray Class को Inherit करके भी Stack Class Create कर सकते हैं, लेकिन ऐसा करना उचित नहीं है। यदि हम public Inheritance का प्रयोग करते हैं तो Stack Class का User safeArray Class के Member Functions को Directly Access कर सकता है। जैसे:

Stack sss;
Sss[2] = 21;

जहां Stack Object इस तरह से Treat किया जा रहा है जैसे वह एक साधारण ।ततंल हो। ये तरीका Stack को Use करने के उद्देश्‍य को कमजोर करता है। यानी एक Stack LIFO सिद्धांत पर काम करता है, लेकिन इस Statement द्वारा Class User Stack के बीच के Data को प्राप्त कर सकता है। हालांकि हम private Inheritance का प्रयोग करके safeArray Class को Class User के लिए Invisible कर सकते हैं, लेकिन फिर भी Stack व safeArray दोनों Classes के बीच एक अनावश्‍यक जटिलता हो जाती है। इसलिए Programming को सरल बना, रखने के लिए Composition का प्रयोग ही उचित है। आप पूछ सकते हैं कि:

Composition के स्थान पर Inheritance को कब Use किया जा सकता है?

इसका जवाब है कि जब Classes के बीच “Kind Of” Relationship का महत्व हो, तब ऐसा किया जा सकता है।  मानलो कि हमारे पास Employees के प्रकार का एक Array है। किसी भी प्रकार के Employees जैसे कि Managers, Scientist या किसी अन्‍य Employee को इस Array में Store करना अच्छा रहता है। जैसे:

Employee empArray[SIZE];
empArray[0] = laborer1;
empArray[1] = scientist1;
empArray[2] = laborer2;

ऐसा हम एक ही स्थिति में कर सकते हैं जब हम विभिन्न प्रकार के Employees को Employee Class से Inherit करें। Composition से Classes के बीच इस प्रकार की Relationship प्राप्त नहीं हो सकती है।  इसी प्रकार की Relationship Shape Class के लिए भी हो सकती है। यदि हम Shape Object को एक square, cap या bowl Class में Data Member की तरह Compose करते हैं, तो हम square को एक shape की तरह Treat नहीं कर सकते हैं। सारांश में कहें तो Composition की विभिन्न Characteristics व तीनों प्रकार के Inheritance को हम निम्नानुसार सारणी के रूप में Represent कर सकते हैं: (Composition over Inheritance – Wiki)

Composition Over Inheritance

CPP Programming Language in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C++ Programming Language in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C++ Programming Language in Hindi | Page: 666 | Format: PDF

BUY NOW GET DEMO REVIEWS