बहुत से लोगों ने पहले ही जवाब दे दिया। सोचा था कि मैं अपना निजी दृष्टिकोण दूंगा।
एक बार मैंने एक ऐप पर काम किया (और अभी भी है) जो संगीत बनाता है।
एप्लिकेशन एक सार था Scale
: कई उपवर्गों के साथ वर्ग CMajor
, DMinor
आदि, Scale
तो कुछ इस तरह देखा:
public abstract class Scale {
protected Note[] notes;
public Scale() {
loadNotes();
}
// .. some other stuff ommited
protected abstract void loadNotes(); /* subclasses put notes in the array
in this method. */
}
संगीत जनरेटर ने Scale
संगीत उत्पन्न करने के लिए एक विशिष्ट उदाहरण के साथ काम किया । उपयोगकर्ता सूची से एक पैमाने का चयन करेगा, जिससे संगीत उत्पन्न किया जा सके।
एक दिन, मेरे दिमाग में एक अच्छा विचार आया: क्यों न उपयोगकर्ता को अपना पैमाना बनाने की अनुमति दें? उपयोगकर्ता सूची से नोट्स का चयन करेगा, एक बटन दबाएगा, और सूची में उपलब्ध तराजू में एक नया पैमाना जोड़ा जाएगा।
लेकिन मैं ऐसा करने में सक्षम नहीं था। ऐसा इसलिए था क्योंकि सभी तराजू पहले से ही संकलित समय पर सेट हैं - क्योंकि उन्हें कक्षाओं के रूप में व्यक्त किया गया है। फिर इसने मुझे मारा:
'सुपरक्लास और उपवर्ग' के संदर्भ में अक्सर सोचना सहज है। लगभग सभी चीजें इस प्रणाली के माध्यम से व्यक्त की जा सकती हैं: सुपरक्लास Person
और उपवर्ग John
और Mary
; सुपरक्लास Car
और उपवर्ग Volvo
और Mazda
; सुपरक्लास Missile
और उपवर्ग SpeedRocked
, LandMine
और TrippleExplodingThingy
।
इस तरह से सोचना बहुत स्वाभाविक है, विशेष रूप से ओओ के लिए अपेक्षाकृत नए व्यक्ति के लिए।
लेकिन हमें हमेशा याद रखना चाहिए कि कक्षाएं टेम्प्लेट हैं , और ऑब्जेक्ट्स इन टेम्प्लेट में डाली गई सामग्री हैं । आप अनगिनत संभावनाओं को बनाते हुए, टेम्पलेट में जो भी सामग्री चाहें डाल सकते हैं।
यह टेम्पलेट को भरने के लिए उपवर्ग का काम नहीं है। यह वस्तु का काम है। उपवर्ग का काम वास्तविक कार्यक्षमता जोड़ना या टेम्पलेट का विस्तार करना है ।
और यही कारण है कि मुझे एक ठोस Scale
वर्ग बनाया जाना चाहिए , एक Note[]
क्षेत्र के साथ , और वस्तुओं को इस टेम्पलेट में भरने दें ; संभवतः निर्माता या कुछ के माध्यम से। और आखिरकार, इसलिए मैंने किया।
हर बार जब आप एक डिजाइन टेम्पलेट (उदाहरण के लिए, एक खाली एक कक्षा में Note[]
सदस्य है कि जरूरतों को भरे जाने के लिए, या एक String name
क्षेत्र है कि जरूरतों को एक मूल्य आवंटित करने के लिए), याद रखें कि यह टेम्पलेट को भरने के लिए इस वर्ग की वस्तुओं के काम है ( या संभवतः इन वस्तुओं को बनाने वाले)। उपवर्गों को कार्यक्षमता जोड़ना है, न कि टेम्प्लेट भरना।
आपको "सुपरक्लास Person
, उपवर्गों " John
और Mary
"इस तरह की" प्रणाली बनाने का लालच दिया जा सकता है , जैसे आपने किया, क्योंकि आपको औपचारिकता पसंद है।
इस तरह, आप बस के Person p = new Mary()
बजाय कह सकते हैं Person p = new Person("Mary", 57, Sex.FEMALE)
। यह चीजों को अधिक संगठित, और अधिक संरचित बनाता है। लेकिन जैसा कि हमने कहा, डेटा के हर संयोजन के लिए एक नया वर्ग बनाना अच्छा तरीका नहीं है, क्योंकि यह कुछ भी नहीं के लिए कोड को ब्लॉट करता है और आपको रनटाइम क्षमताओं के मामले में सीमित करता है।
तो यहाँ एक समाधान है: एक मूल कारखाने का उपयोग करें, यहां तक कि एक स्थिर भी हो सकता है। इस तरह:
public final class PersonFactory {
private PersonFactory() { }
public static Person createJohn(){
return new Person("John", 40, Sex.MALE);
}
public static Person createMary(){
return new Person("Mary", 57, Sex.FEMALE);
}
// ...
}
इस तरह, आप आसानी से 'प्रीसेट्स' को 'प्रोग्राम के साथ आओ' का उपयोग कर सकते हैं, जैसे: Person mary = PersonFactory.createMary()
लेकिन, आप नए व्यक्तियों को गतिशील रूप से डिजाइन करने का अधिकार भी रखते हैं, उदाहरण के लिए उस मामले में जिसे आप उपयोगकर्ता को ऐसा करने की अनुमति देना चाहते हैं। । उदाहरण के लिए:
// .. requesting the user for input ..
String name = // user input
int age = // user input
Sex sex = // user input, interpreted
Person newPerson = new Person(name, age, sex);
या इससे भी बेहतर: ऐसा कुछ करें:
public final class PersonFactory {
private PersonFactory() { }
private static Map<String, Person> persons = new HashMap<>();
private static Map<String, PersonData> personBlueprints = new HashMap<>();
public static void addPerson(Person person){
persons.put(person.getName(), person);
}
public static Person getPerson(String name){
return persons.get(name);
}
public static Person createPerson(String blueprintName){
PersonData data = personBlueprints.get(blueprintName);
return new Person(data.name, data.age, data.sex);
}
// .. or, alternative to the last method
public static Person createPerson(String personName){
Person blueprint = persons.get(personName);
return new Person(blueprint.getName(), blueprint.getAge(), blueprint.getSex());
}
}
public class PersonData {
public String name;
public int age;
public Sex sex;
public PersonData(String name, int age, Sex sex){
this.name = name;
this.age = age;
this.sex = sex;
}
}
मैं आपे से बाहर हो गया। मुझे लगता है कि आपको विचार समझ आ गया है।
उपवर्ग अपने सुपरक्लास द्वारा निर्धारित टेम्प्लेट भरने के लिए नहीं होते हैं। उपवर्गों का मतलब कार्यक्षमता को जोड़ना है । ऑब्जेक्ट टेम्पलेट में भरने के लिए होते हैं, यही वह है जिसके लिए वे हैं।
आपको डेटा के हर संभव संयोजन के लिए एक नया वर्ग नहीं बनाना चाहिए। (ठीक उसी तरह जैसे मुझे Scale
हर संभव संयोजन के लिए एक नया उपवर्ग नहीं बनाना चाहिए Note
)।
एक दिशानिर्देश: जब भी आप एक नया उपवर्ग बनाते हैं, तो विचार करें कि क्या यह कोई नई कार्यक्षमता जोड़ता है जो सुपरक्लास में मौजूद नहीं है। यदि उस प्रश्न का उत्तर "नहीं" है, तो हो सकता है कि आप सुपरक्लास के 'खाके' को भरने की कोशिश कर रहे हों, जिस स्थिति में सिर्फ एक वस्तु का निर्माण करें। (और संभवतः जीवन को आसान बनाने के लिए 'प्रीसेट' के साथ एक कारखाना)।
उम्मीद है की वो मदद करदे।