কীভাবে ডাউন কাস্টিং এড়ানো যায়?


12

আমার প্রশ্নটি সুপার ক্লাস অ্যানিমেলের একটি বিশেষ কেস সম্পর্কে।

  1. আমার Animalক্যান moveForward()এবং eat()
  2. Sealপ্রসারিত Animal
  3. Dogপ্রসারিত Animal
  4. আর একটি বিশেষ প্রাণী যে প্রসারিত এর Animalনামক Human
  5. Humanএকটি পদ্ধতিও speak()প্রয়োগ করে (বাস্তবায়িত হয় না Animal)।

একটি বিমূর্ত পদ্ধতি প্রয়োগের ক্ষেত্রে যা গ্রহণ করে Animalআমি সেই speak()পদ্ধতিটি ব্যবহার করতে চাই । একটানা বাদ দিয়ে তা সম্ভব নয় বলে মনে হচ্ছে। জেরেমি মিলার তার নিবন্ধে লিখেছেন যে একটি নিচে পড়া গন্ধ রয়েছে।

এই পরিস্থিতিতে হতাশাকে এড়ানোর সমাধান কী হবে?


6
আপনার মডেল ঠিক করুন। শ্রেণি শ্রেণিবিন্যাসকে মডেল করার জন্য বিদ্যমান শ্রেণিবৃত্তিক শ্রেণিবিন্যাস ব্যবহার করা সাধারণত ভুল ধারণা। আপনার বিদ্যমান বিধিগুলি থেকে আপনার বিলোপগুলি টানতে হবে, বিমূর্ততা তৈরি করতে হবে না এবং তারপরে কোডটি ফিট করার চেষ্টা করা উচিত।
ইউফোরিক

2
: আপনি কথা বলা প্রাণীদের চান, তাহলে কথা বলার ক্ষমতা কি কিছু একটি প্রাণী তোলে অংশ artima.com/interfacedesign/PreferPoly.html
JeffO

8
সামনে যাও? কাঁকড়া সম্পর্কে কি?
ফ্যাবিও মারকোলিনি

কোন আইটেম # কার্যকর জাভাতে, বিটিডাব্লু?
স্বর্ণলোকস

1
কিছু লোক কথা বলতে পারে না, তাই চেষ্টা করলে ব্যতিক্রম ছুঁড়ে দেওয়া হয়।
তুলিনস কর্ডোভা

উত্তর:


12

যদি আপনার এমন কোনও পদ্ধতি রয়েছে যা জানা দরকার যে নির্দিষ্ট কিছু শ্রেণি করার জন্য নির্দিষ্ট শ্রেণীর প্রকার Humanরয়েছে কি না, তবে আপনি কিছু সলাইড নীতিগুলি ভঙ্গ করছেন , বিশেষত:

  • উন্মুক্ত / বদ্ধ নীতি - যদি ভবিষ্যতে আপনাকে নতুন প্রাণীর প্রকার যুক্ত করতে হয় যা কথা বলতে পারে (উদাহরণস্বরূপ, একটি তোতা), বা সেই ধরণের জন্য নির্দিষ্ট কিছু করতে পারে তবে আপনার বিদ্যমান কোডটি পরিবর্তন করতে হবে
  • ইন্টারফেস বিভাজন নীতি - মনে হচ্ছে আপনি খুব বেশি সাধারণীকরণ করছেন। একটি প্রাণী প্রজাতির বিস্তৃত বর্ণালী coverাকতে পারে।

আমার মতে, যদি আপনার পদ্ধতিটি কোনও নির্দিষ্ট শ্রেণির ধরণের প্রত্যাশা করে, এটির নির্দিষ্ট পদ্ধতি বলে, তবে কেবলমাত্র সেই শ্রেণিটি গ্রহণ করার জন্য সেই পদ্ধতিটি পরিবর্তন করুন, এবং এটি ইন্টারফেস নয়।

এটার মতো কিছু :

public void MakeItSpeak( Human obj );

এবং এই মত না:

public void SpeakIfHuman( Animal obj );

কেউ Animalডেকে একটি বিমূর্ত পদ্ধতিও তৈরি করতে পারে canSpeakএবং প্রতিটি কংক্রিট বাস্তবায়নের ক্ষেত্রে এটি "কথা বলতে পারে" কিনা তা নির্ধারণ করতে হবে।
ব্র্যান্ডন

তবে আমি আপনার উত্তরটি আরও ভাল পছন্দ করি। এমন জটিল কিছু এমন আচরণের চেষ্টা থেকে আসে যা তা নয়।
ব্র্যান্ডন

@ ব্র্যান্ডন আমার ধারণা, সেই ক্ষেত্রে যদি এটি "কথা বলতে" না পারে, তবে তার ব্যতিক্রম ছুঁড়ে ফেলুন। বা শুধু কিছুই না।
BЈовић

সুতরাং আপনি এটির মতো ওভারলোডিং পান: public void makeAnimalDoDailyThing(Animal animal) {animal.moveForward(); animal.eat()}এবংpublic void makeAnimalDoDailyThing(Human human) {human.moveForward(); human.eat(); human.speak();}
বার্ট ওয়েবার

1
সমস্ত পথে যান - MakeItSpeak (ISpeakingAnimal প্রাণী) - এরপরে আপনি ISpeakingAnimal প্রয়োগসমূহ প্রাণী রাখতে পারেন। আপনার কাছে মেকইটস্পেক (পশুর প্রাণী) থাকতে পারে IS যদি আইসপেকিংএনিমাল {তবে কথা বলতে পারেন তবে এতে গন্ধ নেই।
ptyx

6

সমস্যাটি হ'ল আপনি ডাউনকাস্ট করছেন না - এটি হ'ল আপনি ডাউন কাস্ট করছেন Human। পরিবর্তে, একটি ইন্টারফেস তৈরি করুন:

public interface CanSpeak{
    void speak();
}

public abstract class Animal{
    //....
}

public class Human extends Animal implements CanSpeak{
    public void speak(){
        //....
    }
}

public void mysteriousMethod(Animal animal){
    //....
    if(animal instanceof CanSpeak){
        ((CanSpeak)animal).speak();
    }else{
        //Throw exception or something
    }
    //....
}

এইভাবে, শর্তটি প্রাণীটি নয় Human- শর্তটি এটি বলতে পারে। এর অর্থ যতক্ষণ না তারা বাস্তবায়িত হয় ততক্ষণ mysteriousMethodঅন্যান্য, মানবেতর সাব-ক্লাসের সাথে কাজ করতে পারে ।AnimalCanSpeak


এই ক্ষেত্রে এটি যুক্তি হিসাবে পশুর পরিবর্তে ক্যানস্পেকের উদাহরণ হিসাবে নেওয়া উচিত
নিউটোপিয়ান

1
@ নিউটোপিয়ানরা ধরে নিচ্ছেন যে সেই পদ্ধতির কোনও কিছুর প্রয়োজন নেই Animalএবং এই পদ্ধতির সমস্ত ব্যবহারকারীরা কোনও CanSpeakপ্রকার রেফারেন্সের (বা এমনকি Humanরেফারেন্স টাইপ করুন) এর মাধ্যমে তারা যে পাঠাতে চান তা ধরে রাখবেন । যদি এটি হয় তবে সেই পদ্ধতিটি Humanপ্রথম স্থানে ব্যবহার করতে পারত এবং আমাদের প্রবর্তনের দরকার পড়েনি CanSpeak
ইদান আরে

ইন্টারফেস থেকে মুক্তি পাওয়া পদ্ধতির স্বাক্ষরে নির্দিষ্ট হওয়ার সাথে সম্পর্কিত নয় তবে আপনি ইন্টারফেসটি থেকে মুক্তি পেতে পারেন কেবলমাত্র সেখানে যদি কেবলমাত্র একজন মানুষ থাকে এবং কখনও কখনও কেবল "ক্যানস্পেক" থাকে এমন মানুষ হতে পারে।
নিউটোপিয়ান

1
@ নিউপটিয়ান CanSpeakআমাদের প্রথম যে কারণটি চালু করেছিল তা নয় যে আমাদের এমন কিছু রয়েছে যা এটি প্রয়োগ করে ( Human) তবে আমাদের এটি ব্যবহার করে এমন কিছু রয়েছে (পদ্ধতি)। মূল বিষয় CanSpeakহ'ল কংক্রিট শ্রেণি থেকে সেই পদ্ধতিটি ডিকুয়াল করা Human। যদি আমাদের কাছে এমন পদ্ধতি না থাকে যেগুলি জিনিসগুলির সাথে CanSpeakআলাদাভাবে আচরণ করতে পারে তবে জিনিসগুলির মধ্যে পার্থক্য করার কোনও অর্থ নেই CanSpeak। আমাদের একটি পদ্ধতি আছে বলেই আমরা কোনও ইন্টারফেস তৈরি করি না ...
ইডান আরে

2

আপনি প্রাণীর সাথে যোগাযোগ করতে পারেন। কুকুরের ছাঁটা, মানব কথা বলে, সীল .. উহ .. আমি জানি না সীল কী করে।

তবে মনে হচ্ছে আপনার পদ্ধতিটি যদি (প্রাণী হিউম্যান) কথা বলে ();

আপনি যে প্রশ্নটি জানতে চাইতে পারেন তা হ'ল বিকল্প কী? আপনি কী অর্জন করতে চান তা ঠিক জানি না বলে একটি পরামর্শ দেওয়া শক্ত। এমন তাত্ত্বিক পরিস্থিতি রয়েছে যেখানে ডাউন কাস্টিং / আপকাস্টিংই সেরা পন্থা।


15
সীল ow ow ow চলে যায় , কিন্তু শিয়াল অপরিবর্তিত।

2

এই ক্ষেত্রে, ডিফল্ট বাস্তবায়ন speak()মধ্যে AbstractAnimalবর্গ হবে:

void speak() throws CantSpeakException {
  throw new CantSpeakException();
}

এই মুহুর্তে, আপনি অ্যাবস্ট্রাক্ট শ্রেণিতে একটি ডিফল্ট বাস্তবায়ন পেয়েছেন - এবং এটি সঠিকভাবে আচরণ করে।

try {
  thingy.speak();
} catch (CantSeakException e) {
  System.out.println("You can't talk to the " + thingy.name());
}

হ্যাঁ, এর অর্থ হ'ল প্রত্যেকটি হ্যান্ডেল করার জন্য কোডের মাধ্যমে ছড়িয়ে ছিটিয়ে থাকা ট্র্যাচ-ক্যাচগুলি পেয়েছেন speakতবে এর বিকল্পটি if(thingy is Human)পরিবর্তে সমস্ত স্পোক মোড়ানো।

ব্যতিক্রমটির সুবিধাটি হ'ল যদি আপনার কাছে অন্য কোনও ধরণের জিনিস থাকে যা বলার জন্য (একটি তোতা) আপনার সমস্ত পরীক্ষার পুনরায় সংশোধন করার প্রয়োজন হবে না।


1
আমি মনে করি না এটি ব্যতিক্রম ব্যবহার করার জন্য ভাল কারণ (এটি অজগর কোড না হলে)।
ব্রায়ান চেন

1
আমি ভোট হ্রাস করব না কারণ এটি প্রযুক্তিগতভাবে কাজ করবে তবে আমি এই ধরণের নকশাটি পছন্দ করি না। পিতামাতার স্তরে এমন একটি পদ্ধতি কেন সংজ্ঞায়িত করা যা পিতামাতার প্রয়োগ করতে পারে না ? অবজেক্টটি কী ধরণের তা আপনি যদি না জানেন (এবং আপনি যদি করেন তবে - আপনার এই সমস্যাটি হবে না), আপনি সম্পূর্ণরূপে এড়াতে পারা যায় না এমন ব্যতিক্রমগুলি পরীক্ষা করার জন্য আপনাকে সর্বদা চেষ্টা / ক্যাপচ ব্যবহার করতে হবে। canSpeak()এটিকে আরও ভালভাবে পরিচালনা করতে আপনি কোনও পদ্ধতি ব্যবহার করতে পারেন ।
ব্র্যান্ডন

2
আমি এমন একটি প্রকল্পে কাজ করেছি যেটির কারও কারও সিদ্ধান্ত ব্যতীত একটি ব্যতিক্রম ছড়িয়ে দেওয়ার জন্য পুনরায় লিখনের সিদ্ধান্তের সিদ্ধান্ত থেকে উত্পন্ন অনেকগুলি ত্রুটি ছিল কারণ তারা একটি অপ্রচলিত বাস্তবায়ন ব্যবহার করছে। তিনি বাস্তবায়ন স্থির করতে পারতেন, তবে সর্বত্র ব্যতিক্রম ছুঁড়ে দেওয়ার পরিবর্তে বেছে নিয়েছিলেন। স্বাভাবিকভাবেই, আমরা কয়েকশ বাগ সহ কিউএ প্রবেশ করেছি। সুতরাং আমি যে পদ্ধতিগুলিতে কল করা হয় না তার ব্যতিক্রম ছোঁড়ার বিরুদ্ধে পক্ষপাতদুষ্ট। যদি তাদের কল করার কথা না হয় তবে এগুলি মুছুন
ব্র্যান্ডন

2
এক্ষেত্রে ব্যতিক্রম ছোঁড়ার বিকল্প কোনও কিছুই নাও করতে পারে। সব পরে, তারা কথা বলতে পারে না :)
BЈовић

@ ব্র্যান্ডনের ব্যতিক্রমের সাথে এটির নকশা শুরু থেকে পরবর্তীতে পুনরায় নকশার মধ্যে পার্থক্য রয়েছে। জাভা 8-এ একটি ডিফল্ট পদ্ধতিযুক্ত ইন্টারফেসের দিকেও নজর দেওয়া যেতে পারে, বা কোনও ব্যতিক্রম ছুঁড়ে না দিয়ে চুপ করে থাকা। যদিও মূল বিষয়টি হ'ল ডাউনকাস্টের প্রয়োজন এড়াতে ফাংশনটি যে ধরণের পাস হবে তাতে সংজ্ঞায়িত করা দরকার।

1

ডাউন কাস্টিং কখনও কখনও প্রয়োজনীয় এবং উপযুক্ত হয়। বিশেষত, এটির ক্ষেত্রে বেশিরভাগ ক্ষেত্রে উপযুক্ত হয় যেখানে কারও কিছু ক্ষমতা থাকতে পারে বা নাও থাকতে পারে এবং যখন কোনও দক্ষতা ছাড়াই কোনও ডিফল্ট ফ্যাশনে অবজেক্টগুলি পরিচালনা করতে থাকে তখন সেই ক্ষমতাটি ব্যবহার করার ইচ্ছা থাকে wishes একটি সাধারণ উদাহরণ হিসাবে ধরা যাক, Stringএটিকে জিজ্ঞাসা করা হয়েছে যে এটি কিছু অন্যরকম বস্তুর সমান কিনা equal একের Stringসাথে অন্যকে সমান করার জন্য String, এটি অবশ্যই অন্য স্ট্রিংয়ের দৈর্ঘ্য এবং ব্যাকিং অক্ষরের অ্যারে পরীক্ষা করতে হবে। যদি Stringএটির জিজ্ঞাসা করা হয় এটি একটি সমান কিনা Dog, তবে এটি দৈর্ঘ্যের অ্যাক্সেস করতে পারে না Dog, তবে এটি করার দরকার নেই; পরিবর্তে, যেটির Stringসাথে নিজেকে তুলনা করার কথা বলে তা যদি একটি না হয়String, তুলনাটি একটি ডিফল্ট আচরণ ব্যবহার করা উচিত (অন্য বিষয় সমান নয় বলে প্রতিবেদন করা)।

ডাউন কাস্টিংকে সবচেয়ে সন্দেহজনক হিসাবে গণ্য করা উচিত যখন কাস্ট করা অবজেক্টটি সঠিক ধরণের হতে "পরিচিত" হয় of সাধারণভাবে, যদি কোনও বস্তু a হিসাবে পরিচিত হয় Catতবে তার উল্লেখের জন্য ব্যক্তির পরিবর্তকের Catপরিবর্তে টাইপের পরিবর্তক ব্যবহার করা উচিত Animal। কিছু সময় আছে যখন এটি সর্বদা কার্যকর হয় না। উদাহরণস্বরূপ, Zooসংগ্রহটি জোড় / বিজোড় অ্যারে স্লটগুলিতে জোড়া বস্তু ধারণ করতে পারে, এই প্রত্যাশা সহ যে প্রতিটি জোড়ের বস্তুগুলি একে অপরের উপর কাজ করতে সক্ষম হবে, এমনকি যদি তারা অন্য জোড়ের বস্তুগুলিতে কাজ করতে না পারে। এই জাতীয় ক্ষেত্রে, প্রতিটি জোড়ের অবজেক্টগুলিকে এখনও কোনও নির্দিষ্ট-নির্দিষ্ট প্যারামিটার ধরণের গ্রহণ করতে হবে যেমন তারা সিন্ট্যাক্টিকভাবে , অন্য কোনও জুড়ি থেকে অবজেক্টগুলি পাস করতে পারে। সুতরাং, এমনকি যদি CatএরplayWith(Animal other)পদ্ধতিটি কেবল তখনই কাজ করবে যখন এটি otherছিল Cat, Zooএটির কোনও উপাদানটি পাস করার প্রয়োজন হবে Animal[], সুতরাং এর পরামিতিটির ধরণের Animalপরিবর্তে হওয়া উচিত Cat

যেসব ক্ষেত্রে ডাউন কাস্টিং বৈধভাবে অপরিহার্য, সেখানে কাউকে বিনা বাছাই করা উচিত। মূল প্রশ্নটি নির্ধারণ করা হচ্ছে যে কখন কোনও সংজ্ঞাগতভাবে ডাউন কাস্টিং এড়াতে পারে এবং সংবেদনশীলভাবে সম্ভব হলে এড়ানো উচিত।


স্ট্রিং ক্ষেত্রে, আপনার পরিবর্তে একটি পদ্ধতি থাকা উচিত Object.equalToString(String string)। তারপরে আপনার boolean String.equal(Object object) { return object.equalStoString(this); }তাই, কোনও হতাশাব্যঞ্জক প্রয়োজন নেই: আপনি গতিশীল প্রেরণ ব্যবহার করতে পারেন।
জর্জিও

@ জর্জিও: ডায়নামিক প্রেরণের ব্যবহার রয়েছে তবে এটি সাধারণত ডাউন কাস্টিংয়ের চেয়েও খারাপ।
সুপারক্যাট

ডাইনামিক প্রেরণটি সাধারণত ডাউনকাস্টিংয়ের চেয়েও খারাপ? আমি যদিও এটি অন্য পথে
ব্রায়ান চেন

@ ব্রায়ানচেন: এটি আপনার পরিভাষার উপর নির্ভর করে। আমার Objectকোনও equalStoStringভার্চুয়াল পদ্ধতি আছে বলে আমি মনে করি না , এবং আমি স্বীকার করব যে উদ্ধৃত উদাহরণটি জাভাতে কীভাবে কাজ করবে তা আমি জানি না, তবে সি # তে ডায়নামিক প্রেরণ (ভার্চুয়াল প্রেরণের চেয়ে পৃথক) এর অর্থ সংকলকটি মূলত কোনও ক্লাসে প্রথমবার কোনও পদ্ধতি ব্যবহার করার পরে প্রতিচ্ছবি-ভিত্তিক নাম অনুসন্ধান করতে, যা ভার্চুয়াল প্রেরণের থেকে পৃথক (যা কেবল ভার্চুয়াল পদ্ধতি টেবিলের একটি স্লটের মাধ্যমে কল করে যা একটি বৈধ পদ্ধতির ঠিকানা থাকতে হবে)।
সুপারক্যাট

মডেলিং দৃষ্টিকোণ থেকে, আমি সাধারণভাবে গতিশীল প্রেরণ পছন্দ করব। এটি এর ইনপুট প্যারামিটার (গুলি) এর ধরণের ভিত্তিতে কোনও পদ্ধতি নির্বাচন করার অবজেক্ট-ওরিয়েন্টেড উপায়।
জর্জিও

1

একটি বিমূর্ত পদ্ধতি প্রয়োগের ক্ষেত্রে যা প্রাণীকে গ্রহণ করে আমি স্পোক () পদ্ধতিটি ব্যবহার করতে চাই।

আপনার কয়েকটি পছন্দ আছে:

  • speakএটি উপস্থিত থাকলে কল করার জন্য প্রতিবিম্ব ব্যবহার করুন । সুবিধা: কোনও নির্ভরতা নেই Human। অসুবিধা: এখন "কথা বলুন" নামের উপর একটি গোপন নির্ভরতা রয়েছে।

  • একটি নতুন ইন্টারফেস Speakerএবং ইন্টারফেস ডাউন ডাউনকাস্ট পরিচয় করিয়ে দিন । নির্দিষ্ট কংক্রিটের উপর নির্ভর করে এটি আরও নমনীয়। এটির অসুবিধা রয়েছে যা Humanবাস্তবায়নের জন্য আপনাকে পরিবর্তন করতে হবে Speaker। আপনি সংশোধন করতে না পারলে এটি কাজ করবে নাHuman

  • ডাউনকাস্ট টু Human। এটির অসুবিধা রয়েছে যে আপনি যখনই অন্য সাবক্লাসের সাথে কথা বলতে চান তখন আপনাকে কোডটি সংশোধন করতে হবে। আদর্শভাবে আপনি বারবার ফিরে না গিয়ে এবং পুরানো কোড পরিবর্তন না করে কোড যুক্ত করে অ্যাপ্লিকেশনগুলি প্রসারিত করতে চান।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.