কম মিলন এবং আঁটসাঁটো মিলন


11

অবশ্যই এটি পরিস্থিতির উপর নির্ভর করে। কিন্তু যখন একটি নিম্ন লিভার অবজেক্ট বা সিস্টেম একটি উচ্চ স্তরের সিস্টেমের সাথে যোগাযোগ করে, কলব্যাকস বা ইভেন্টগুলি কি উচ্চ স্তরের অবজেক্টে একটি পয়েন্টার রাখার পক্ষে অগ্রাধিকার দেওয়া উচিত?

উদাহরণস্বরূপ, আমাদের একটি worldক্লাস রয়েছে যার একটি সদস্য ভেরিয়েবল রয়েছে vector<monster> monstersmonsterক্লাসটি যখন যোগাযোগ করে world, তখন আমি কি কলব্যাক ফাংশনটি ব্যবহার করতে পছন্দ করব বা worldক্লাসের অভ্যন্তরে আমার কাছে একটি পয়েন্টার থাকা উচিত monster?


প্রশ্নের শিরোনামে বানান বাদে, এটি আসলে কোনও প্রশ্নের আকারে বর্ণিত হয় না। আমি মনে করি এটি পুনরায় বিতরণ আপনি এখানে যা জিজ্ঞাসা করছেন তা দৃify় করতে সহায়তা করবে, যেহেতু আমি মনে করি না যে আপনি এই প্রশ্নের বর্তমান আকারে একটি দরকারী উত্তর পেতে পারেন। এবং এটি গেম-ডিজাইনের প্রশ্নও নয়, এটি প্রোগ্রামিং কাঠামোর উপর একটি প্রশ্ন (এটির অর্থ ডিজাইন ট্যাগটি উপযুক্ত কিনা তা নিশ্চিত নয়, আমরা 'সফ্টওয়্যার ডিজাইন' এবং ট্যাগগুলিতে কোথায় নেমেছি তা মনে করতে পারে না)
মিঃ ক্র্যাঙ্কি

উত্তর:


10

এখানে তিনটি প্রধান উপায় রয়েছে যা একটি শ্রেণীর সাথে শক্তভাবে মিলিত না হয়ে অন্যের সাথে কথা বলতে পারে:

  1. একটি কলব্যাক ফাংশন মাধ্যমে।
  2. একটি ইভেন্ট সিস্টেমের মাধ্যমে।
  3. একটি ইন্টারফেস মাধ্যমে।

তিনটি একে অপরের সাথে নিবিড়ভাবে জড়িত। একটি ইভেন্ট সিস্টেম বিভিন্ন উপায়ে কেবল কলব্যাকের একটি তালিকা। একটি কলব্যাক একক পদ্ধতিতে কমবেশি ইন্টারফেস।

সি ++ তে আমি খুব কমই কলব্যাক ব্যবহার করি:

  1. সি ++ এর কলব্যাকগুলির জন্য ভাল সমর্থন নেই যা তাদের thisপয়েন্টার ধরে রাখে , তাই অবজেক্ট-ওরিয়েন্টেড কোডে কলব্যাকগুলি ব্যবহার করা শক্ত।

  2. একটি কলব্যাক মূলত একটি অ-এক্সটেনসেবল ওয়ান-পদ্ধতি ইন্টারফেস। সময়ের সাথে সাথে, আমি দেখতে পেলাম যে ইন্টারফেসটি সংজ্ঞায়িত করার জন্য আমার প্রায়শই একাধিক পদ্ধতির প্রয়োজন হয় এবং একক কলব্যাক খুব কমই যথেষ্ট।

এই ক্ষেত্রে, আমি সম্ভবত একটি ইন্টারফেস করব। আপনার প্রশ্নে, আপনি আসলে কী বানান করেন নাmonster কথোপকথনের প্রয়োজনworld । অনুমান করে, আমি এই জাতীয় কিছু করব:

class IWorld {
public:
  virtual Monster* getNearbyMonster(const Position & position) = 0;
  virtual Item*    getItemAt(const Position & position) = 0;
};

class Monster {
public:
  void update(IWorld * world) {
    // Do stuff...
  }
}

class World : public IWorld {
public:
  virtual Monster* getNearbyMonster(const Position & position) {
    // ...
  }

  virtual Item*    getItemAt(const Position & position) {
    // ...
  }

  // Lots of other stuff that Monster should not have access to...
}

এখানে ধারণাটি হ'ল আপনি কেবলমাত্র IWorld(যা একটি কৃপণ নাম) অল্প অল্প অল্প Monsterঅ্যাক্সেসের দরকার তা রেখেছেন in বিশ্বের দৃষ্টিভঙ্গি যতটা সম্ভব সংকীর্ণ হওয়া উচিত।


1
+1 প্রতিনিধিরা (কলব্যাকস) সময় যত বেশি যায় তত সাধারণত আরও অসংখ্য হয়ে যায়। দানবদের যাতে তারা স্টাফ পেতে পারে তার জন্য একটি ইন্টারফেস দেওয়া আমার মতে যাওয়ার ভাল উপায়।
মাইকেল কোলম্যান

12

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

আমি একে একে সেরা অনুশীলন বলব না, তবে তাদের পিতামাতার কাছে নির্দেশক থাকার জন্য এমন কিছু সত্তা থাকা সত্তা থাকা একটি সাধারণ প্যাটার্ন।

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


+1 দানবকে পিতামাতার কাছে কল করার সীমিত উপায় দেওয়া আমার মতে একটি দুর্দান্ত মধ্যম উপায়।
মাইকেল কলম্যান

7

সাধারণত আমি দ্বি-নির্দেশমূলক লিঙ্কগুলি চেষ্টা করি এবং এড়িয়ে চলি, তবে আমার যদি সেগুলি অবশ্যই থাকে তবে আমি অবশ্যই নিশ্চিত করে রাখি যে সেগুলি তৈরি করার একটি পদ্ধতি আছে এবং সেগুলি ভেঙে ফেলার জন্য একটি পদ্ধতি রয়েছে, যাতে আপনি কখনই অসঙ্গতি না পান।

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

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


3

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

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

আপনার ক্ষেত্রে অন্য একটি বিকল্প, আমি সম্ভবত বুঝতে পারি কেন দানব শ্রেণীর বিশ্বব্যাপী সম্পর্কে জানতে হবে এবং আপনি সম্ভবত খুঁজে পাবেন যে বিশ্ব শ্রেণিতে এমন কিছু আছে যা তার নিজের একটি শ্রেণিতে বিভক্ত হতে পারে that দানব বর্গ সম্পর্কে জানার জন্য বোধ।


2

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

আসুন একটি "ধ্রুপদী" পরিস্থিতি গ্রহণ করুন, একটি দানব কোনও খেলোয়াড়কে আক্রমণ করে।

দানব আক্রমণ করছে: পৃথিবী খুব ভালভাবে পরিস্থিতি সনাক্ত করতে পারে যেখানে কোনও নরকের পাশে একটি নায়ক থাকে এবং দৈত্যটিকে আক্রমণ করতে বলে tell সুতরাং দানব মধ্যে ফাংশন হবে:

void Monster::attack(LivingCreature l)
{
  // Call to combat system
}

কিন্তু দুনিয়া (যারা ইতিমধ্যে দানবকে জানে) দানব দ্বারা জানার দরকার নেই। আসলে, দৈত্যটি ক্লাস ওয়ার্ল্ডের খুব অস্তিত্বকে উপেক্ষা করতে পারে, যা সম্ভবত আরও ভাল।

দানবটি চলতে থাকলে একই জিনিস (আমি সাব-সিস্টেমগুলি প্রাণীটিকে পেতে এবং তার জন্য সরানো গণনা / অভিপ্রায় পরিচালনা করতে দেই, দানবটি কেবলমাত্র একটি ব্যাগ হ'ল, তবে প্রচুর লোকেরা বলবে এটি আসল ওওপি নয়)।

আমার বক্তব্যটি: ইভেন্টগুলি (বা কলব্যাক) অবশ্যই দুর্দান্ত, তবে আপনি যে প্রতিটি সমস্যার মুখোমুখি হবেন তার একমাত্র উত্তর নয়।


1

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

একটি উপায় হ'ল পদ্ধতি কলের রিটার্ন মানটিতে আরও তথ্য অন্তর্ভুক্ত করা হয় যার অর্থ ক্লায়েন্ট কোড পদ্ধতিটি তার নিয়ন্ত্রণ ফিরে আসার পরে এটি দিয়ে কী করবে তা সিদ্ধান্ত নিতে পারে।

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

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

  • এটি আমার অবজেক্টগুলিকে আরও আলগাভাবে জুড়ে রাখে। আমার অবজেক্টগুলি অন্যান্য বস্তুগুলিকে আবদ্ধ করতে পারে তবে তারা কখনই কলারের প্রসঙ্গে নির্ভর করবে না এবং প্রসঙ্গটি কখনই এমপ্ল্যাপুলেটেড অবজেক্টের উপর নির্ভর করবে না।
  • এটি আমার নিয়ন্ত্রণ প্রবাহকে যুক্তিযুক্তভাবে সহজ রাখে। এটি ধরে নিতে পেরে খুব ভাল লাগল যে selfকোনও পদ্ধতি কার্যকর করার সময় কেবলমাত্র কোডটি অভ্যন্তরীণ অবস্থার পরিবর্তন করতে পারে তা হ'ল একটি পদ্ধতি এবং অন্য কোনও নয়। এটি একই ধরণের যুক্তি যা সমবর্তী বস্তুগুলিতে মিটেক্স লাগাতে পারে।
  • এটি আমার অবজেক্টগুলির এনক্যাপসুলেটেড ডেটাতে আক্রমণকারীদের রক্ষা করে। আক্রমণকারীদের উপর নির্ভর করার জন্য পাবলিক পদ্ধতিগুলি অনুমোদিত হয় এবং যদি কোনও পদ্ধতি বহিরাগতভাবে বলা যেতে পারে এবং অন্যটি ইতিমধ্যে কার্যকর করা হয় তবে এই আক্রমণকারীদের লঙ্ঘন করা যেতে পারে।

আমি কলব্যাকের সমস্ত ব্যবহারের বিরুদ্ধে নই। কখনই "কলকারীকে ফোন করা" না করার বিষয়ে আমার নীতিমালার সাথে তাল মিলিয়ে যদি কোনও বস্তু A বি তে কোনও পদ্ধতি আহ্বান করে এবং তাতে একটি কলব্যাক পাস করে, কলব্যাক এ এর ​​অভ্যন্তরীণ অবস্থার পরিবর্তন করতে পারে না এবং এর মধ্যে ক এবং আ দ্বারা আবৃত বস্তুগুলি অন্তর্ভুক্ত রয়েছে এ এর প্রসঙ্গে বস্তু অন্য কথায়, কলব্যাক কেবল বি দ্বারা প্রদত্ত বস্তুর জন্য পদ্ধতিগুলি আহ্বান করতে পারে call কলব্যাক, বাস্তবে, বি এর একই বিধিনিষেধের অধীনে।

বেঁধে দেওয়ার এক শেষ looseিলে শেষটি হ'ল আমি যে আংশিক ক্রমটি সম্পর্কে কথা বলছি তা নির্বিশেষে আমি কোনও খাঁটি ফাংশন প্রার্থনার অনুমতি দেব। খাঁটি ফাংশনগুলি এমন পদ্ধতিগুলির থেকে কিছুটা পৃথক যে তারা পরিবর্তন করতে পারে না বা পরিবর্তিত অবস্থা বা পার্শ্ব প্রতিক্রিয়াগুলির উপর নির্ভর করতে পারে, তাই তাদের বিভ্রান্তিকর বিষয়ে কোনও উদ্বেগ নেই।


0

ব্যক্তিগতভাবে? আমি কেবল একটি সিঙ্গলটন ব্যবহার করি।

হ্যাঁ, ঠিক আছে, খারাপ নকশা, বস্তু-ভিত্তিক নয়, ইত্যাদি আপনি কী জানেন? আমি পাত্তা দিই না । আমি একটি গেম লিখছি, কোনও প্রযুক্তি শোকেস নয়। কেউ আমাকে কোডে গ্রেড করা যাচ্ছে না। উদ্দেশ্যটি হ'ল মজাদার একটি গেম তৈরি করা এবং আমার পথে যা কিছু আসে তার ফলস্বরূপ কম খেলা হয় less

আপনি কি একবারে দু'টি পৃথিবী চালাবেন? হতে পারে! হতে পারে আপনি। তবে যদি আপনি এই মুহূর্তে সেই পরিস্থিতিটি ভাবতে না পারেন তবে আপনি সম্ভবত তা করবেন না।

সুতরাং, আমার সমাধান: একটি ওয়ার্ল্ড সিঙ্গলটন করুন। এটিতে ফাংশন কল করুন। পুরো জগাখিচুড়ি দিয়ে করা। আপনি পারে প্রতি একক ফাংশন একটি অতিরিক্ত প্যারামিটার মধ্যে পাস - এবং কোন ভুল, যে যেখানে এই বিশালাকার ভুলবেন না। অথবা আপনি ঠিক যে কোড লিখতে পারে কাজ করে।

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

এবং আপনি যদি সিদ্ধান্ত নেন যে আপনি আর কোনও সিঙ্গলটন চান না, তবে এটি থেকে মুক্তি পাওয়া সাধারণত সহজ। কিছুটা কাজ নেয়, প্রায় এক বিলিয়ন প্যারামিটারগুলি কেটে নেয়, তবে সেগুলি এমন প্যারামিটার যা আপনাকে যে কোনও উপায়ে পাস করতে হবে।


2
আমি সম্ভবত এটি আরও কিছুটা সংক্ষেপে বলতে চাই: "রিফ্যাক্টর করতে ভয় পাবেন না"।
টেট্রাড

সিঙ্গেলন দুষ্ট! গ্লোবালগুলি আরও ভাল। আপনি তালিকাভুক্ত একক গুণাবলী সমস্ত গ্লোবালের জন্য একই। আমি আমার বিভিন্ন উপ-সিস্টেমে গ্লোবাল পয়েন্টার (প্রকৃতপক্ষে বিশ্বব্যাপী ফাংশনগুলি রেফারেন্সগুলি রিটার্ন করে) ব্যবহার করি এবং এগুলি আমার মূল ফাংশনে তাদের আরম্ভ / বিনষ্ট করি। গ্লোবাল পয়েন্টারগুলি ইনিশিয়ালাইজেশন অর্ডার সংক্রান্ত সমস্যাগুলি, টিয়ার ডাউন করার সময় সিঙ্গেলনগুলিকে ঝাঁকুনি দেওয়া, সিঙ্গেলনের অ-তুচ্ছ নির্মাণ ইত্যাদি এড়াতে পারে I
deft_code

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