मेरी कक्षा किताब (शुरुआती OOP) में कक्षाओं के पदानुक्रम से भी बदतर क्यों है?


11

मैं PHP ऑब्जेक्ट्स, पैटर्न और अभ्यास पढ़ रहा हूं । लेखक एक कॉलेज में एक पाठ को मॉडल करने की कोशिश कर रहा है। लक्ष्य पाठ प्रकार (व्याख्यान या संगोष्ठी) का उत्पादन करना है, और सबक के लिए शुल्क इस पर निर्भर करता है कि यह एक प्रति घंटा या निश्चित मूल्य पाठ है। तो आउटपुट होना चाहिए

Lesson charge 20. Charge type: hourly rate. Lesson type: seminar.
Lesson charge 30. Charge type: fixed rate. Lesson type: lecture.

जब इनपुट इस प्रकार है:

$lessons[] = new Lesson('hourly rate', 4, 'seminar');
$lessons[] = new Lesson('fixed rate', null, 'lecture');

मैंने यह लिखा:

class Lesson {
    private $chargeType;
    private $duration;
    private $lessonType;

    public function __construct($chargeType, $duration, $lessonType) {
        $this->chargeType = $chargeType;
        $this->duration = $duration;
        $this->lessonType = $lessonType;
    }

    public function getChargeType() {
        return $this->getChargeType;
    }

    public function getLessonType() {
        return $this->getLessonType;
    }

    public function cost() {
        if($this->chargeType == 'fixed rate') {
            return "30";
        } else {
            return $this->duration * 5;
        }
    }
}

$lessons[] = new Lesson('hourly rate', 4, 'seminar');
$lessons[] = new Lesson('fixed rate', null, 'lecture');

foreach($lessons as $lesson) {
    print "Lesson charge {$lesson->cost()}.";
    print " Charge type: {$lesson->getChargeType()}.";
    print " Lesson type: {$lesson->getLessonType()}.";
    print "<br />";
}

लेकिन किताब के मुताबिक, मैं गलत हूं (मुझे पूरा यकीन है कि मैं भी हूं)। इसके बजाय, लेखक ने समाधान के रूप में कक्षाओं की एक बड़ी पदानुक्रम दी। पिछले अध्याय में, लेखक ने निम्नलिखित 'चार साइनपोस्ट' को उस समय के रूप में कहा था जब मुझे अपनी कक्षा संरचना को बदलने पर विचार करना चाहिए:

एकमात्र समस्या जो मैं देख सकता हूं, वह है सशर्त बयान, और वह भी अस्पष्ट तरीके से - तो क्यों यह रिफ्लेक्टर? आपको क्या लगता है कि भविष्य में क्या समस्याएँ पैदा हो सकती हैं, जिन्हें मैंने दूर नहीं किया है?

अद्यतन : मैं उल्लेख करना भूल गया - यह वर्ग संरचना है जिसे लेखक ने समाधान के रूप में प्रदान किया है - रणनीति पैटर्न :

रणनीति पैटर्न


29
PHP पुस्तक से ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग न सीखें।
जीओर्गिओसिरोनी

4
@giorgiosironi मैंने भाषाओं का मूल्यांकन करना छोड़ दिया है। मैं दैनिक आधार पर PHP का उपयोग करता हूं, और इसलिए मेरे लिए इसमें नई अवधारणाएं सीखना सबसे तेज़ है। वहाँ हमेशा लोग हैं, जो एक भाषा से नफरत कर रहे हैं (जावा: slidesha.re/91C4pX ) - बेशक यह पीएचपी dissers से जावा नापसंद करने को खोजने के लिए कठिन है, लेकिन अभी भी। PHP के OO के साथ समस्याएं हो सकती हैं, लेकिन फिलहाल मैं जावा सिंटैक्स, "जावा तरीका", और OOP सीखने के लिए समय नहीं बचा सकता । इसके अलावा, डेस्कटॉप प्रोग्रामिंग मेरे लिए विदेशी है। मैं एक संपूर्ण वेब व्यक्ति हूं। लेकिन इससे पहले कि आप JSP में जा सकें, आपको कथित तौर पर डेस्कटॉप जावा (कोई उद्धरण, क्या मैं गलत हूं?) जानने की आवश्यकता है
आदित्य एमपी

तार के बजाय "स्थिर दर" / "प्रति घंटा की दर" और "संगोष्ठी" / "व्याख्यान" के लिए स्थिरांक का उपयोग करें।
टॉम मार्थेनल

जवाबों:


19

यह मज़ेदार है कि यह पुस्तक स्पष्ट रूप से नहीं बताती है , लेकिन यही कारण है कि यह एक वर्ग पदानुक्रम का पक्ष लेता है यदि एक ही वर्ग के अंदर के बयान संभवतः खुले / बंद सिद्धांत हैं यह व्यापक रूप से ज्ञात सॉफ़्टवेयर डिज़ाइन नियम बताता है कि एक वर्ग बंद होना चाहिए संशोधन लेकिन विस्तार के लिए खुला।

आपके उदाहरण में, एक नया पाठ प्रकार जोड़ने का मतलब होगा कि पाठ वर्ग के स्रोत कोड को बदलना, यह नाजुक और प्रतिगमन प्रवण बनाता है। यदि आपके पास प्रत्येक पाठ प्रकार के लिए एक आधार वर्ग और एक व्युत्पन्न है, तो आपको इसके बजाय बस एक और उपवर्ग जोड़ना होगा, जो आमतौर पर क्लीनर के रूप में होता है।

आप उस नियम को "सशर्त विवरण" खंड के तहत रख सकते हैं यदि आप करेंगे, हालांकि मैं समझता हूं कि "साइनपोस्ट" थोड़ा अस्पष्ट है। यदि बयान आम तौर पर सिर्फ कोड महक, लक्षण हैं। वे खराब डिजाइन निर्णयों की एक विस्तृत विविधता से परिणाम कर सकते हैं।


3
यह विरासत के बजाय एक कार्यात्मक विस्तार का उपयोग करने के लिए एक बहुत अच्छा विचार होगा।
डेडजैम

6
समस्या के लिए निश्चित रूप से अन्य / बेहतर दृष्टिकोण हैं। हालाँकि, यह स्पष्ट रूप से ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग और खुले / बंद सिद्धांत के बारे में एक पुस्तक है, जिसने मुझे OO में इस तरह के डिजाइन दुविधा के दृष्टिकोण के शास्त्रीय तरीके के रूप में मारा ।
गुरिल्ला

समस्या का सबसे अच्छा तरीका कैसे है ? वहाँ कोई मतलब नहीं है एक अवर समाधान शिक्षण क्योंकि यह ऊ है।
डेडजैम

16

मुझे लगता है कि शिक्षण के उद्देश्य से पुस्तक का उद्देश्य क्या है:

public function cost() {
    if($this->chargeType == 'fixed rate') {
        return "30";
    } else {
        return $this->duration * 5;
    }
}

पुस्तक की मेरी व्याख्या यह है कि आपके पास तीन कक्षाएं होनी चाहिए:

  • AbstractLesson
  • HourlyRateLesson
  • FixedRateLesson

फिर आपको costदोनों उपवर्गों पर फ़ंक्शन को फिर से लागू करना चाहिए ।

मेरी निजी राय

इस तरह के सरल मामलों के लिए: नहीं। यह अजीब है कि आपकी पुस्तक सरल सशर्त बयानों से बचने के लिए गहरी श्रेणी पदानुक्रम का पक्षधर है। क्या अधिक है, आपके इनपुट कल्पना के Lessonसाथ, एक प्रेषण के साथ एक कारखाना बनना होगा जो एक सशर्त बयान है। तो पुस्तक समाधान के साथ आपके पास होगा:

  • 1 के बजाय 3 कक्षाएं
  • 0 के बजाय 1 विरासत का स्तर
  • सशर्त विवरणों की समान संख्या

यह अधिक जटिलता है जिसमें कोई अतिरिक्त लाभ नहीं है।


8
में इस मामले , हाँ, यह बहुत अधिक जटिलता है। लेकिन एक बड़ा प्रणाली में, आप और अधिक सबक, की तरह जोड़ने की जाएगी SemesterLesson, MasterOneWeekLessonआदि एक सार जड़ वर्ग, या बेहतर अभी तक एक अंतरफलक, निश्चित रूप से तो जाने के लिए रास्ता है। लेकिन जब आपके पास केवल दो मामले हैं, तो यह लेखक के विवेक पर निर्भर है।
माइकल के

5
मैं आपसे सामान्य रूप से सहमत हूं। हालांकि, शैक्षिक उदाहरणों को अक्सर एक बिंदु को चित्रित करने के लिए और अधिक वंचित किया जाता है। आप एक पल के लिए अन्य विचारों को अनदेखा कर देते हैं ताकि हाथ में समस्या न आए, और बाद में उन विचारों को पेश करें।
कार्ल बेवफेल्ट

+1 अच्छा पूरी तरह से टूटने। टिप्पणी, "यह बिना किसी अतिरिक्त लाभ के साथ अधिक जटिलता है" प्रोग्रामिंग में 'अवसर लागत' की अवधारणा को पूरी तरह से दिखाता है। सिद्धांत! = व्यावहारिकता।
इवान प्लाइस

7

पुस्तक में उदाहरण बहुत अजीब है। आपके प्रश्न से, मूल कथन यह है:

लक्ष्य पाठ प्रकार (व्याख्यान या संगोष्ठी) का उत्पादन करना है, और पाठ के लिए शुल्क इस बात पर निर्भर करता है कि यह एक प्रति घंटा या निश्चित मूल्य पाठ है।

ओओपी पर एक अध्याय के संदर्भ में, इसका मतलब यह होगा कि लेखक शायद आपको निम्नलिखित संरचना देना चाहता है:

+ abstract Lesson
    - Lecture inherits Lesson
    - Seminar inherits Lesson

+ abstract Charge
    - HourlyCharge inherits Charge
    - FixedCharge inherits Charge

लेकिन फिर आपके द्वारा उद्धृत इनपुट आता है:

$lessons[] = new Lesson('hourly rate', 4, 'seminar');
$lessons[] = new Lesson('fixed rate', null, 'lecture');

यानी कुछ जिसे कड़ाई से टाइप किया गया कोड कहा जाता है , और जो, ईमानदारी से, इस संदर्भ में जब पाठक को ओओपी सीखने का इरादा है, भयानक है।

इसका मतलब यह भी है कि अगर मैं पुस्तक लेखक के इरादे के बारे में सही हूं (अर्थात उन सार और विरासत में मिली कक्षाएं जिन्हें मैंने ऊपर सूचीबद्ध किया है), तो इससे डुप्लिकेट और सुंदर अपठनीय और बदसूरत कोड हो जाएगा:

const string $HourlyRate = 'hourly rate';
const string $FixedRate = 'fixed rate';

// [...]

Charge $charge;
switch ($chargeType)
{
    case $HourlyRate:
        $charge = new HourlyCharge();
        break;

    case $FixedRate:
        $charge = new FixedCharge();
        break;

    default:
        throw new ParserException('The value of chargeType is unexpected.');
}

// Imagine the similar code for lecture/seminar, and the similar code for both on output.

"साइनपोस्ट" के लिए:

  • कोड डुप्लीकेशन

    आपके कोड में दोहराव नहीं है। लेखक आपको लिखने की उम्मीद करता है कोड।

  • क्लास जो अपने संदर्भ के बारे में बहुत जानता था

    आपकी कक्षा इनपुट से आउटपुट तक स्ट्रिंग्स पास करती है, और कुछ भी नहीं जानती है। दूसरी ओर अपेक्षित कोड की बहुत अधिक जानने के लिए आलोचना की जा सकती है।

  • जैक ऑफ ऑल ट्रेड्स - कक्षाएं जो कई चीजें करने की कोशिश करती हैं

    फिर, आप सिर्फ तार गुजर रहे हैं, और कुछ नहीं।

  • सशर्त बयान

    आपके कोड में एक सशर्त विवरण है। यह पठनीय और समझने में आसान है।


हो सकता है, वास्तव में, लेखक को उम्मीद थी कि आप ऊपर के छह वर्गों के साथ एक से अधिक परिष्कृत कोड लिखेंगे। उदाहरण के लिए आप पाठ और शुल्क आदि के लिए कारखाने के पैटर्न का उपयोग कर सकते हैं ।

+ abstract Lesson
    - Lecture inherits Lesson
    - Seminar inherits Lesson

+ abstract Charge
    - HourlyCharge inherits Charge
    - FixedCharge inherits Charge

+ LessonFactory

+ ChargeFactory

+ Parser // Uses factories to transform the input into `Lesson`.

इस मामले में, आप नौ वर्गों के साथ समाप्त होंगे, जो एक अति-वास्तुकला का एक आदर्श उदाहरण होगा ।

इसके बजाय, आप आसानी से समझने वाले, साफ कोड के साथ समाप्त हो गए, जो दस गुना कम है।


वाह, आपके अनुमान सटीक हैं! मेरे द्वारा अपलोड की गई छवि को देखें - लेखक ने ठीक उसी चीजों की सिफारिश की।
आदित्य एमपी

मैं होता तो क्या यह उत्तर स्वीकार करने के लिए प्यार करता हूँ, लेकिन ओह, मैं क्या करूँ मैं भी @ ian31 के जवाब :( की तरह!
आदित्य सांसद

5

सबसे पहले आप "मैजिक नंबर" को बदल सकते हैं जैसे 30 और 5 इन कॉस्ट () फंक्शन को अधिक अर्थपूर्ण चर के लिए :)

और ईमानदार होने के लिए, मुझे लगता है कि आपको इस बारे में चिंता नहीं करनी चाहिए। जब आपको कक्षा बदलने की आवश्यकता होगी तब आप इसे बदल देंगे। पहले मूल्य बनाने की कोशिश करें फिर रिफैक्टराइजेशन पर जाएं।

और आप यह क्यों सोच रहे हैं कि आप गलत हैं? क्या यह वर्ग आपके लिए "अच्छा" नहीं है? आप किसी किताब को लेकर चिंतित क्यों हैं;)


1
जवाब के लिए धन्यवाद! दरअसल, रिफ्लेक्टरिंग बाद में आएगी। हालाँकि, मैंने सीखने के लिए इस कोड को लिखा, अपने तरीके से पुस्तक में प्रस्तुत समस्या को हल करने की कोशिश की और यह देखा कि मैं कैसे गलत हो जाता हूं ...
आदित्य एमपी

2
लेकिन ये आपको बाद में पता चलेगा। जब इस वर्ग का उपयोग सिस्टम के अन्य भागों में किया जाएगा और आपको कुछ नया जोड़ना होगा। कोई "सिल्वर बुलेट" समाधान नहीं है :) कुछ अच्छा या बुरा हो सकता है यह सिस्टम, आवश्यकताओं आदि पर निर्भर करता है। ओओपी सीखने के दौरान आपको बहुत कुछ विफल करना होगा: पी फिर समय के साथ आपको कुछ सामान्य समस्याएं और पैटर्न दिखाई देंगे। Tbh यह उदाहरण कुछ सलाह देने के लिए बहुत सरल है। ओह, मैं वास्तव में जोएल से इस पोस्ट की सिफारिश करता हूं: आर्किटेक्चरल अंतरिक्ष यात्री joelonsoftware.com/items/2008/05/01.html
Michal Franc

@adityamenon तो आपका जवाब है "रिफैक्टरिंग बाद में आएगी"। कोड को सरल बनाने के लिए आवश्यक होने पर ही अन्य वर्गों को जोड़ें - आमतौर पर, जब तृतीय समान उपयोग का मामला आता है। देखें साइमन का जवाब।
इज़काता 14

3

किसी भी अतिरिक्त कक्षाओं को लागू करने के लिए बिल्कुल कोई आवश्यकता नहीं है। आपको MAGIC_NUMBERअपने cost()फ़ंक्शन में थोड़ी समस्या है , लेकिन ऐसा है। कुछ भी एक बड़े पैमाने पर अधिक इंजीनियरिंग है। हालाँकि, यह दुर्भाग्य से आम है कि बहुत बुरी सलाह दी जा सकती है- उदाहरण के लिए सर्किल विरासत में मिला है। यह निश्चित रूप से एक फ़ंक्शन के साधारण वंशानुक्रम के लिए एक वर्ग प्राप्त करने के लिए किसी भी तरह से कुशल नहीं है। आप इसके बजाय इसे अनुकूलित करने के लिए एक कार्यात्मक दृष्टिकोण का उपयोग कर सकते हैं।


1
यह दिलचस्प है। क्या आप बता सकते हैं कि आप एक उदाहरण के साथ ऐसा कैसे करेंगे?
गिलोय

+1, मैं सहमत हूं, इस तरह के एक छोटे से कार्यक्षमता को ओवर-इंजीनियर / जटिल करने का कोई कारण नहीं है।
ग्रैंडमास्टरबी

@ ian31: क्या, विशेष रूप से?
डेडजैम

@DeadMG "एक कार्यात्मक दृष्टिकोण का उपयोग करें", "वंशानुक्रम के बजाय एक कार्यात्मक विस्तार का उपयोग करें"
guillaume31
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.