সাবক্লাসের ধরণ জিজ্ঞাসা করা এড়াতে ভাল ডিজাইনের অনুশীলন কী?


11

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

abstract class Shape {
  ShapeType getType();
  bool collide(Shape other);
}

class Circle : Shape {
  getType() { return Type.Circle; }

  bool collide(Shape other) {
    if(other.getType() == Type.Rect) {
      collideCircleRect(this, (Rect) other);     
    } else if(other.getType() == Type.Polygon) {
      collideCirclePolygon(this, (Polygon) other);
    }
  }
}

এটি কি একটি খারাপ ডিজাইনের ধরণ? সাবক্লাসের ধরণগুলি না বুঝে আমি কীভাবে এটি সমাধান করতে পারি?


1
আপনি শেষ করেছেন যে প্রতিটি দৃষ্টান্ত যেমন চেনাশোনা প্রতিটি অন্যান্য শেপ-টাইপগুলি জানে। সুতরাং তারা সব একরকম দৃ solid়ভাবে সংযুক্ত। এবং ত্রিভুজগুলির মতো আপনি কোনও নতুন আকার যুক্ত করার সাথে সাথে আপনি সর্বত্র ট্রায়াঙ্গল সমর্থন যোগ করবেন। আপনি আরও বেশি পরিবর্তন করতে চান তার উপর এটি নির্ভর করে, আপনি কি নতুন আকার যুক্ত করবেন, এই নকশাটি খারাপ is আপনার সমাধান বিস্তৃত হওয়ার কারণে - আপনার ত্রিভুজগুলির সমর্থনটি সর্বত্র জুড়ে থাকতে হবে। পরিবর্তে আপনার নিজের সংঘর্ষকে আলাদা ক্লাসে বের করা উচিত, যা সমস্ত ধরণের এবং প্রতিনিধিদের সাথে কাজ করতে পারে।
thepacker


আইএমও এটি কর্মক্ষমতা প্রয়োজনীয়তায় নেমে আসে। আরও সুনির্দিষ্ট কোডটি তত বেশি অনুকূলিত হতে পারে এবং এটি তত দ্রুত চালিত হবে। এই বিশেষ ক্ষেত্রে (এটা বাস্তবায়িত খুব), লিখুন চেক ঠিক আছে কারণ উপযোগী সংঘর্ষের চেক হতে পারে enourmously দ্রুত একটি জেনেরিক সমাধান নয়। তবে যখন রানটাইম পারফরম্যান্স সমালোচনা না করে, আমি সর্বদা সাধারণ / বহুমুখী পদ্ধতির সাথে যেতে চাই।
মার্সাতাতো

সকলকে ধন্যবাদ, আমার ক্ষেত্রে পারফরম্যান্সটি সমালোচিত এবং আমি নতুন আকার যুক্ত করব না, সম্ভবত আমি কলসিডিশন এপ্রোচ করি, তবে এখনও সাবক্লাসের ধরণটি আমার জানা ছিল, আমি কি "টাইপ গেটটাইপ ()" পদ্ধতিটি রাখা উচিত? শেপ বা তার পরিবর্তে কোলিশন ডিটেকশন ক্লাসে শেপের সাথে কিছু ধরণের "উদাহরণস্বরূপ" করছেন?
আলেজান্দ্রো

1
বিমূর্ত Shapeবস্তুর মধ্যে কার্যকর কোনও সংঘর্ষের পদ্ধতি নেই । আপনার যুক্তি অন্য অবজেক্টের অভ্যন্তরগুলির উপর নির্ভর করে যদি না আপনি সীমানা পয়েন্টের জন্য সংঘর্ষের পরীক্ষা করছেন bool collide(x, y)(কন্ট্রোল পয়েন্টগুলির একটি উপসেটটি একটি ভাল ট্রেড অফ হতে পারে)। অন্যথায় আপনাকে কোনওভাবে টাইপ পরীক্ষা করতে হবে - যদি সত্যিই বিমূর্ততার প্রয়োজন হয় তবে Collisionধরণের উত্পাদন (বর্তমান অভিনেতার ক্ষেত্রের মধ্যে থাকা বস্তুর জন্য) সঠিক পন্থা হওয়া উচিত।
কাঁপুন

উত্তর:


13

পলিমরফিজ্ম

আপনি যতক্ষণ getType()না এটি ব্যবহার করেন বা ব্যবহার করেন না ততক্ষণ আপনি বহুকর্ম ব্যবহার করছেন না।

আমি বুঝতে পারছি যে আপনার কী ধরণের তা জানা দরকার। তবে যে কাজ আপনি করতে চান তা জানতে পেরে ক্লাসে আসলেই চাপ দেওয়া উচিত। তারপরে আপনি এটি কখন করবেন তা বলুন।

কার্যবিধি কোড তথ্য পায় তারপর সিদ্ধান্ত নেয়। অবজেক্ট-ওরিয়েন্টেড কোড বস্তুগুলিকে জিনিস করতে বলে।
- অ্যালেক শার্প

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

encapsulation

আপনি আমাকে বলতে পারবেন যে অন্য কোনও আকারের আর প্রয়োজন হবে না তবে আমি আপনাকে বিশ্বাস করি না এবং আপনারও করা উচিত নয়।

এনক্যাপসুলেশন অনুসরণ করার একটি দুর্দান্ত প্রভাব এটি হ'ল নতুন প্রকার যুক্ত করা সহজ কারণ তাদের বিবরণটি কোডটিতে ছড়িয়ে পড়ে না যেখানে তারা প্রদর্শিত হয় ifএবং switchযুক্তি দেয়। একটি নতুন ধরণের কোড সমস্ত এক জায়গায় থাকা উচিত।

এক প্রকার অজ্ঞান সংঘর্ষ সনাক্তকরণ সিস্টেম

আসুন আমি আপনাকে দেখাতে পারি যে আমি কীভাবে সংঘর্ষ সনাক্তকরণ সিস্টেমটি ডিজাইন করব যা পারফরম্যান্ট এবং প্রকারের বিষয়ে চিন্তা না করে কোনও 2 ডি আকারের সাথে কাজ করে।

এখানে চিত্র বর্ণনা লিখুন

বলুন যে আপনি আঁকার কথা ছিল। সহজ মনে হচ্ছে। এটি সমস্ত চেনাশোনা। সংঘর্ষগুলি বোঝে এমন একটি বৃত্ত শ্রেণি তৈরি করা লোভনীয়। সমস্যাটি হ'ল এটি আমাদের চিন্তাভাবনার এক লাইনে প্রেরণ করে যা যখন আমাদের 1000 টি বৃত্তের প্রয়োজন হয় তখন বিচ্ছিন্ন হয়ে যায়।

আমাদের চেনাশোনাগুলি সম্পর্কে চিন্তা করা উচিত নয়। আমাদের পিক্সেল সম্পর্কে চিন্তা করা উচিত।

যদি আমি আপনাকে বলেছিলাম যে এই ছেলেদের আঁকতে আপনি একই কোডটি ব্যবহার করেন তারা হ'ল তারা স্পর্শ করার সময় বা এমনকি ব্যবহারকারী কোনটি ক্লিক করছে তা সনাক্ত করতে আপনি ব্যবহার করতে পারেন

এখানে চিত্র বর্ণনা লিখুন

এখানে আমি প্রতিটি চেনাশোনা একটি অনন্য রঙ দিয়ে আঁকলাম (যদি আপনার চোখ কালো বর্ণরেখা দেখতে যথেষ্ট ভাল হয় তবে কেবল তা উপেক্ষা করুন)। এর অর্থ এই লুকানো চিত্রের প্রতিটি পিক্সেল এটি কী আঁকে তার পিছনে maps একটি হ্যাশম্যাপ সেই সুন্দরভাবে যত্ন করে। আপনি আসলে এইভাবে পলিমারফিজম করতে পারেন।

এই চিত্রটি আপনাকে কখনই ব্যবহারকারীর কাছে দেখাতে হবে না। আপনি এটি একই কোডটি দিয়ে তৈরি করেন যা প্রথমটি আঁকে। ঠিক বিভিন্ন রঙের সাথে।

যখন ব্যবহারকারী একটি চেনাশোনাতে ক্লিক করে আমি ঠিক জানি কোন বৃত্তটি কারণ কেবলমাত্র একটি বৃত্তই সেই রঙ।

যখন আমি অন্যটির উপরে একটি বৃত্ত আঁকাম আমি দ্রুত প্রতি পিক্সেলটি সেটে ফেলে দিয়ে ওভাররাইট করতে যাচ্ছি read যখন আমি প্রতিটি বৃত্তের সেট পয়েন্টগুলি সম্পন্ন করেছি তখন এটির সংঘর্ষ হয়েছিল এবং এখন সংঘর্ষের বিষয়টি জানাতে আমাকে কেবল একবার ফোন করতে হবে।

একটি নতুন প্রকার: আয়তক্ষেত্রগুলি

এগুলি সমস্তই চেনাশোনাগুলির সাথে করা হয়েছিল তবে আমি আপনাকে জিজ্ঞাসা করছি: এটি আয়তক্ষেত্রগুলির সাথে কোনও আলাদা কাজ করবে?

কোনও বৃত্ত জ্ঞান সনাক্তকরণ সিস্টেমে ফাঁস হয়নি। এটি ব্যাসার্ধ, পরিধি বা কেন্দ্র বিন্দু সম্পর্কে চিন্তা করে না। এটি পিক্সেল এবং রঙ সম্পর্কে যত্নশীল।

এই সংঘর্ষের সিস্টেমটির একমাত্র অংশ যা পৃথক আকারের নীচে ঠেলাঠেলি করা দরকার এটি একটি অনন্য রঙ। শেপগুলি ছাড়াও শেপগুলি কেবল তাদের শেপগুলি আঁকার বিষয়ে ভাবতে পারে। যাইহোক তারা ভাল কি এটি।

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

বাস্তবায়ন পছন্দ

সত্যিই, এটি কোনও অনন্য রঙ হওয়ার দরকার নেই। এটি প্রকৃত অবজেক্ট রেফারেন্স হতে পারে এবং ইন্ডিয়ারেশনের একটি স্তর বাঁচাতে পারে। কিন্তু এই উত্তরটি আঁকলে সেগুলি এত সুন্দর লাগবে না।

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

ডাবল প্রেরণ

এখনও অবধি আমি ডাবল প্রেরণকে সম্পূর্ণ উপেক্ষা করেছি । আমি পেরেছি বলেই পেরেছি। এতক্ষণ পর্যন্ত যে সংঘর্ষের যুক্তি যত্ন করে না যে কোন দুটি ধরণের সংঘর্ষ আপনার প্রয়োজন হবে না। আপনার যদি এটির প্রয়োজন না হয় তবে এটি ব্যবহার করবেন না। যদি আপনি মনে করেন যে আপনার এটির প্রয়োজন হতে পারে তবে আপনি যতক্ষণ পারেন তা মোকাবেলা বন্ধ করুন। এই মনোভাবকে YAGNI বলা হয়

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

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

এর অর্থ যখন আমার টর্পেডো এমন কিছু আঘাত করে যা ক্ষতি গ্রহণ করে তা জানার দরকার নেই যে এটি কোনও স্পেস শিপকে আঘাত করে hit এটি কেবল এটিই বলতে হবে, "হা হা! আপনি ক্ষতির 5 পয়েন্ট নিয়েছিলেন।"

যে জিনিসগুলির ক্ষতি হয় সেগুলি ক্ষতির বার্তা গ্রহণ করে এমন ক্ষতিকারক বার্তাগুলি প্রেরণ করে। অন্য আকারকে নতুন আকৃতি সম্পর্কে কিছু না জানিয়ে আপনি নতুন আকার যুক্ত করতে পারেন সেভাবে হয়ে গেছে। আপনি কেবল নতুন ধরণের সংঘর্ষের চারদিকে ছড়িয়ে পড়েছেন।

স্পেস শিপটি "হা হা! আপনি 100 পয়েন্টের ক্ষতির ক্ষতি করে নিয়েছিলেন" টর্পে ফেরত পাঠাতে পারেন। পাশাপাশি "আপনি এখন আমার ঝাঁকুনিতে আটকে গেছেন"। এবং টর্পটি "ঠিক আছে, আমি আমার সম্পর্কে ভুলে যাচ্ছি" এর জন্য ফিরে পাঠাতে পারে।

কোন মুহুর্তে হয় প্রতিটি সঠিক কি জানেন না। সংঘর্ষের ইন্টারফেসের মাধ্যমে কীভাবে একে অপরের সাথে কথা বলতে হয় তা তারা জানে।

এখন নিশ্চিত, ডাবল প্রেরণ আপনাকে এর থেকে আরও ঘনিষ্ঠভাবে নিয়ন্ত্রণ করতে দেয় তবে আপনি কি সত্যিই এটি চান ?

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

কর্মক্ষমতা

অভিনয় সর্বদা সমালোচনামূলক। তবে এর অর্থ এই নয় যে এটি সর্বদা একটি সমস্যা। টেস্ট পারফরম্যান্স। শুধু অনুমান করবেন না। পারফরম্যান্সের নামে অন্য যে কোনও কিছুকে ত্যাগ করার পরে সাধারণত কোনওভাবেই পারফরম্যান্ট কোড হয় না।



+1 এর জন্য "আপনি আমাকে বলতে পারবেন যে অন্য কোনও আকারের আর প্রয়োজন হবে না তবে আমি আপনাকে বিশ্বাস করি না এবং
আপনাকেও করা

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

7

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

এমনকি উইকিপিডিয়া নিবন্ধেও একই সংঘর্ষের রূপক ব্যবহার করা হয়েছে, আমাকে কেবল উদ্ধৃত করা যাক (পাইথনের অন্য কয়েকটি ভাষার মতো মাল্টিমিথডগুলি অন্তর্নির্মিত নেই):

@multimethod(Asteroid, Asteroid)
def collide(a, b):
    """Behavior when asteroid hits asteroid"""
    # ...define new behavior...
@multimethod(Asteroid, Spaceship)
def collide(a, b):
    """Behavior when asteroid hits spaceship"""
    # ...define new behavior...
# ... define other multimethod rules ...

সুতরাং, পরবর্তী প্রশ্নটি হল আপনার প্রোগ্রামিং ভাষায় মাল্টিমিডাডসের সমর্থন কীভাবে পাবেন।



হ্যাঁ, একাধিক প্রেরণ ওরফে মাল্টিমিথথডসের বিশেষ ক্ষেত্রে, উত্তরে যুক্ত করা হয়েছে
রোমান সুসি

5

এই সমস্যাটির জন্য দুটি স্তরে পুনরায় নকশা প্রয়োজন।

আকারের বাইরে আকারগুলির মধ্যে সংঘর্ষ সনাক্ত করার জন্য আপনাকে প্রথমে যুক্তিটি ছড়িয়ে দিতে হবে। এটি হ'ল প্রতিবার আপনাকে মডেলটিতে একটি নতুন আকার যুক্ত করার দরকার পরে আপনি ওসিপি লঙ্ঘন করবেন না । আপনি ইতিমধ্যে সার্কেল, স্কোয়ার এবং আয়তক্ষেত্র সংজ্ঞায়িত করেছেন তা কল্পনা করুন। আপনি এটির পরে এটি করতে পারেন:

class ShapeCollisionDetector
{
    public void DetectCollisionCircleCircle(Circle firstCircle, Circle secondCircle)
    { 
        //Code that detects collision between two circles
    }

    public void DetectCollisionCircleSquare(Circle circle, Square square)
    {
        //Code that detects collision between circle and square
    }

    public void DetectCollisionCircleRectangle(Circle circle, Rectangle rectangle)
    {
        //Code that detects collision between circle and rectangle
    }

    public void DetectCollisionSquareSquare(Square firstSquare, Square secondSquare)
    {
        //Code that detects collision between two squares
    }

    public void DetectCollisionSquareRectangle(Square square, Rectangle rectangle)
    {
        //Code that detects collision between square and rectangle
    }

    public void DetectCollisionRectangleRectangle(Rectangle firstRectangle, Rectangle secondRectangle)
    { 
        //Code that detects collision between two rectangles
    }
}

এরপরে, আপনাকে অবশ্যই যথাযথ পদ্ধতিটি কল করার আকৃতির উপর নির্ভর করে কল করার জন্য ব্যবস্থা করতে হবে। পলিমারফিজম এবং ভিজিটর প্যাটার্ন ব্যবহার করে আপনি এটি করতে পারেন । এটি অর্জন করার জন্য, আমাদের অবশ্যই যথাযথ অবজেক্ট মডেল থাকা উচিত। প্রথমত, সমস্ত আকারের একই ইন্টারফেসটি মেনে চলতে হবে:

    interface IShape
{
    void DetectCollision(IShape shape);
    void Accept (ShapeVisitor visitor);
}

এর পরে, আমাদের অবশ্যই একটি পিতামাতাক্রমী দর্শনার্থী ক্লাস থাকতে হবে:

    abstract class ShapeVisitor
{
    protected ShapeCollisionDetector collisionDetector = new ShapeCollisionDetector();

    abstract public void VisitCircle (Circle circle);

    abstract public void VisitSquare(Square square);

    abstract public void VisitRectangle(Rectangle rectangle);

}

আমি ইন্টারফেসের পরিবর্তে এখানে একটি ক্লাস ব্যবহার করছি, কারণ আমার কাছে প্রতিটি দর্শকের অবজেক্টের ShapeCollisionDetectorধরণের বৈশিষ্ট্য থাকতে হবে ।

IShapeইন্টারফেসের প্রতিটি বাস্তবায়ন উপযুক্ত দর্শনার্থীকে তাত্ক্ষণিকভাবে কল করে Acceptএবং কলিং অবজেক্টটি যার সাথে ইন্টারেক্ট করে তার উপযুক্ত পদ্ধতিটিকে কল করে :

    class Circle : IShape
{
    public void DetectCollision(IShape shape)
    {
        CircleVisitor visitor = new CircleVisitor(this);
        shape.Accept(visitor);
    }

    public void Accept(ShapeVisitor visitor)
    {
        visitor.VisitCircle(this);
    }
}

    class Rectangle : IShape
{
    public void DetectCollision(IShape shape)
    {
        RectangleVisitor visitor = new RectangleVisitor(this);
        shape.Accept(visitor);
    }

    public void Accept(ShapeVisitor visitor)
    {
        visitor.VisitRectangle(this);
    }
}

এবং নির্দিষ্ট দর্শনার্থীরা এর মতো দেখতে পাবেন:

    class CircleVisitor : ShapeVisitor
{
    private Circle Circle { get; set; }

    public CircleVisitor(Circle circle)
    {
        this.Circle = circle;
    }

    public override void VisitCircle(Circle circle)
    {
        collisionDetector.DetectCollisionCircleCircle(Circle, circle);
    }

    public override void VisitSquare(Square square)
    {
        collisionDetector.DetectCollisionCircleSquare(Circle, square);
    }

    public override void VisitRectangle(Rectangle rectangle)
    {
        collisionDetector.DetectCollisionCircleRectangle(Circle, rectangle);
    }
}

    class RectangleVisitor : ShapeVisitor
{
    private Rectangle Rectangle { get; set; }

    public RectangleVisitor(Rectangle rectangle)
    {
        this.Rectangle = rectangle;
    }

    public override void VisitCircle(Circle circle)
    {
        collisionDetector.DetectCollisionCircleRectangle(circle, Rectangle);
    }

    public override void VisitSquare(Square square)
    {
        collisionDetector.DetectCollisionSquareRectangle(square, Rectangle);
    }

    public override void VisitRectangle(Rectangle rectangle)
    {
        collisionDetector.DetectCollisionRectangleRectangle(Rectangle, rectangle);
    }
}

এইভাবে, প্রতিবার নতুন আকার যুক্ত করার সময় আপনাকে আকারের ক্লাসগুলি পরিবর্তন করার দরকার হবে না এবং উপযুক্ত সংঘর্ষ সনাক্তকরণের পদ্ধতিটি কল করার জন্য আপনাকে আকারের ধরণের পরীক্ষা করতে হবে না।

এই সমাধানটির একটি অপূর্ণতা হ'ল যদি আপনি একটি নতুন আকৃতি যুক্ত করেন তবে আপনাকে সেই আকৃতির (উদাহরণস্বরূপ VisitTriangle(Triangle triangle)) পদ্ধতির সাহায্যে শেপভিসিটার শ্রেণিটি প্রসারিত করতে হবে এবং ফলস্বরূপ, আপনাকে অন্য সমস্ত দর্শনার্থীদের ক্ষেত্রে সেই পদ্ধতিটি প্রয়োগ করতে হবে। তবে, যেহেতু এটি এক্সটেনশন, এই অর্থে যে কোনও বিদ্যমান পদ্ধতি পরিবর্তিত হয়নি, তবে কেবলমাত্র একটি নতুন যুক্ত করা হয়েছে, এটি ওসিপি লঙ্ঘন করে না , এবং কোড ওভারহেড ন্যূনতম। এছাড়াও, ক্লাসটি ব্যবহার করে ShapeCollisionDetectorআপনি এসআরপি লঙ্ঘন এড়াতে পারবেন এবং কোড অপ্রয়োজনীয়তা এড়াতে পারবেন।


5

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

মূল ধারণাটি হ'ল আপনি বহুবার বহুবচন ব্যবহার করেন twice যখন দুটি আকারের সংঘর্ষ হয় আপনি পলিমারফিজমের মাধ্যমে কোনও একটির সঠিক সংঘর্ষের পদ্ধতিটি কল করতে পারেন এবং জেনেরিক শেপের ধরণের অন্য অবজেক্টটি পাস করতে পারেন। তথাকথিত পদ্ধতিতে আপনি জানতে পারবেন যে এই বস্তুটি একটি বৃত্ত, আয়তক্ষেত্র বা যা কিছু is তারপরে আপনি সংঘাতের পদ্ধতিটি পাস করা আকারের অবজেক্টে কল করুন এবং এটি এই বস্তুকে পাস করুন । এই দ্বিতীয় কলটি আবার পলিমারফিজমের মাধ্যমে সঠিক অবজেক্টের ধরণটি আবিষ্কার করে।

abstract class Shape {
  bool collide(Shape other);
  bool collide(Rect other);
  bool collide(Circle other);
}

class Circle : Shape {

  bool collide(Shape other) {
    return other.collide(this);
  }

  bool collide(Rect other) {
    // algorithm to detect collision between Circle and Rect
  }

  // ...
}

class Rect : Shape {

  bool collide(Shape other) {
    return other.collide(this);
  }

  bool collide(Circle other) {
    // algorithm to detect collision between Circle and Rect
  }

  // ...
}

এই কৌশলটির একটি বড় অসুবিধা হ'ল, শ্রেণিবদ্ধ প্রতিটি শ্রেণির সমস্ত ভাইবোন সম্পর্কে জানতে হবে। এটি পরে একটি নতুন আকৃতি যুক্ত করা হলে এটি একটি উচ্চ রক্ষণাবেক্ষণ বোঝা রাখে।


2

এই সমস্যাটির কাছে যাওয়ার জন্য এটি সর্বোত্তম উপায় নয়

ম্যাথ বেহিঙ শেপ সংঘর্ষটি আকৃতির সংমিশ্রণের জন্য বিশেষ। এর অর্থ যে আপনি যে সাব-রুটিনগুলির প্রয়োজন হবে সেটি হ'ল আপনার সিস্টেম সমর্থন করে এমন আকারের বর্গক্ষেত্র। আকৃতির সংঘর্ষগুলি আসলে আকারগুলিতে অপারেশন নয়, তবে অপারেশনগুলি যা আকারগুলি পরামিতি হিসাবে গ্রহণ করে।

অপারেটর ওভারলোড কৌশল

আপনি যদি অন্তর্নিহিত গণিত সমস্যাটিকে সহজতর করতে না পারেন তবে আমি অপারেটরকে ওভারলোড পদ্ধতির পুনরুদ্ধার করব। কিছুটা এইরকম:

 public final class ShapeOp 
 {
     static { ... }

     public static boolean collision( Shape s1, Shape s2 )  { ... }
     public static boolean collision( Point p1, Point p2 ) { ... }
     public static boolean collision( Point p1, Square s1 ) { ... }
     public static boolean collision( Point p1, Circle c1 ) { ... }
     public static boolean collision( Point p1, Line l1 ) { ... }
     public static boolean collision( Square s1, Point p2 ) { ... }
     public static boolean collision( Square s1, Square s2 ) { ... }
     public static boolean collision( Square s1, Circle c1 ) { ... }
     public static boolean collision( Square s1, Line l1 ) { ... }
     (...)

স্ট্যাটিক ইনটালাইজারে আমি জেনেরিক সংঘর্ষে (শেপ এস 1, শেপ এস 2) পদ্ধতিতে ডায়নামিক ডিসপ্রেটার প্রয়োগের পদ্ধতিগুলির মানচিত্র তৈরি করতে প্রতিবিম্বটি ব্যবহার করব। স্ট্যাটিক ইনটালাইজারটি ক্লাস লোড করতে অস্বীকার করে সংঘর্ষের ফাংশনগুলি সনাক্ত করার জন্য এবং তাদের প্রতিবেদন করার জন্য যুক্তিও রাখতে পারে।

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

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

সম্ভব হলে আপনার গণিতের সমস্যাটি সরল করুন

যেমনটি আমি উল্লেখ করেছি যে সংঘর্ষের ফাংশনগুলির সংখ্যা হ'ল আকারের সংখ্যার বর্গক্ষেত্র। এর অর্থ হল যে কেবলমাত্র 20 টি আকারের সিস্টেমে আপনার 400 রুটিনের প্রয়োজন হবে, 21 আকারের 441 এবং আরও। এটি সহজেই এক্সটেনসিবল নয়।

তবে আপনি আপনার গণিতকে সহজ করতে পারেন । সংঘর্ষের ক্রিয়াটি প্রসারিত করার পরিবর্তে আপনি প্রতিটি আকারকে রাস্টারাইজ করতে বা ত্রিভুজ করতে পারেন। এইভাবে সংঘর্ষের ইঞ্জিনটি এক্সটেনসিবল হওয়ার দরকার নেই। সংঘর্ষ, দূরত্ব, ছেদ, একত্রীকরণ এবং অন্যান্য বিভিন্ন ফাংশন সর্বজনীন হবে।

triangulate

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

আবার ... আপনার একক সংঘর্ষের ফাংশন হবে। আপনার ক্লাস তখন হয়ে যায়:

public class Shape 
{
    public Triangle[] triangulate();
}

এবং আপনার অপারেশন:

public final class ShapeOp
{
    public static boolean collision( Triangle[] shape1, Triangle[] shape2 )
}

সহজ তাই না?

Rasterize

একক সংঘর্ষের ফাংশন রাখতে আপনি নিজের আকারটিকে রাস্টারাইজ করতে পারেন।

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

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

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