ইন্টারফেস ডিজাইন যেখানে ফাংশনগুলিকে একটি নির্দিষ্ট ক্রমে ডাকা প্রয়োজন


24

কাজটি হ'ল কিছু ইনপুট স্পেসিফিকেশন অনুসারে ডিভাইসের মধ্যে একটি হার্ডওয়্যার টুকরা কনফিগার করা। এটি নিম্নলিখিত হিসাবে অর্জন করা উচিত:

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

2) এটি স্পষ্ট হওয়ার পরে যে আর কোনও অনুরোধগুলি আদায় হচ্ছে না, একটি সূচনা কমান্ড, অনুরোধকৃত সংস্থার সংক্ষিপ্তসার প্রদান করে, হার্ডওয়্যারটিতে প্রেরণ করা দরকার।

৩) কেবলমাত্র তার পরে, (এবং অবশ্যই) উক্ত সংস্থানগুলির বিশদ কনফিগারেশন করা যেতে পারে।

৪) এছাড়াও, কেবল ২ এর পরে), ঘোষিত কলারের কাছে নির্বাচিত সংস্থাগুলির (এবং অবশ্যই) রুটিং করা যেতে পারে।


বাগগুলির জন্য একটি সাধারণ কারণ, এমনকি আমার পক্ষে, যিনি জিনিসটি লিখেছিলেন, তারা এই ক্রমটি ভুল করছেন। প্রথমবারের মতো কোডটি দেখে এমন ব্যক্তির দ্বারা ইন্টারফেসটি ব্যবহারের যোগ্য করে তুলতে আমি কোন নামকরণের সম্মেলন, ডিজাইন বা পদ্ধতি ব্যবহার করতে পারি?


মঞ্চ 1 আরও ভাল বলা হয় discoveryবা handshake?
রওয়ং

1
টেম্পোরাল কাপলিং একটি অ্যান্টি-প্যাটার্ন এবং এড়ানো উচিত।

1
প্রশ্নের শিরোনাম আমাকে ভাবায় যে আপনি ধাপে নির্মাতা প্যাটার্নে আগ্রহী
জোশুয়া টেলর

উত্তর:


45

এটি একটি নতুন ডিজাইন কিন্তু আপনি অনেকগুলি API এর অপব্যবহার রোধ করতে পারেন তবে কল করা উচিত নয় এমন কোনও পদ্ধতি উপলব্ধ নেই।

উদাহরণস্বরূপ, পরিবর্তে first you init, then you start, then you stop

আপনার কনস্ট্রাক্টর initএমন একটি জিনিস যা শুরু করা যায় এবং startএকটি সেশন তৈরি করে যা থামানো যায়।

অবশ্যই যদি আপনার এক সময় একটি অধিবেশন করার সীমাবদ্ধতা থাকে তবে আপনাকে কেসটি পরিচালনা করতে হবে যেখানে কেউ ইতিমধ্যে সক্রিয় সাথে একটি তৈরির চেষ্টা করে।

এখন সেই কৌশলটি আপনার নিজের ক্ষেত্রে প্রয়োগ করুন।


zlibএবং jpeglibদুটি উদাহরণ যা সূচনা করার জন্য এই প্যাটার্নটি অনুসরণ করে। তবুও, বিকাশকারীদের ধারণাটি শেখাতে প্রচুর ডকুমেন্টেশন প্রয়োজন।
রওয়ং

5
এটি ঠিক সঠিক উত্তর: যদি আদেশের বিষয়টি বিবেচনা করে তবে প্রতিটি ফাংশন এমন ফলাফল দেয় যা পরবর্তী পদক্ষেপটি সম্পাদন করার জন্য আহ্বান জানানো যেতে পারে। সংকলক নিজেই ডিজাইনের সীমাবদ্ধতাগুলি প্রয়োগ করতে সক্ষম।

2
এটি ধাপ নির্মাতার প্যাটার্নের মতো ; কেবলমাত্র একটি ইন্টারফেসটি উপস্থাপন করুন যা নির্দিষ্ট পর্যায়ে উপলব্ধি করে।
জোশুয়া টেলর

@ জোশুয়া টেইলর আমার উত্তরটি এক ধাপ নির্মাতা প্যাটার্ন বাস্তবায়ন :)
সিলভিউ বুর্সিয়া

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

19

আপনি স্টার্টআপ পদ্ধতিতে এমন কোনও বস্তু ফিরিয়ে আনতে পারেন যা কনফিগারেশনে প্রয়োজনীয় প্যারামিটার:

রিসোর্স * মাইমডুল :: গেটআরসোর্স ();
মাইসেশন * মাইমডুল :: স্টার্টআপ ();
অকার্যকর রিসোর্স :: কনফিগার (মাই সেশন * সেশন);

এমনকি যদি আপনার MySessionকেবল একটি খালি কাঠামো, তবে এটি প্রকারের সুরক্ষার মাধ্যমে প্রয়োগ করবে যে কোনও Configure()পদ্ধতি প্রারম্ভের আগে ডাকা যাবে না।


কাউকে কি করতে বাধা দেয় module->GetResource()->Configure(nullptr)?
সুইভ

@ এসভিক: কিছুই নয়, তবে আপনাকে অবশ্যই এটি স্পষ্টভাবে করতে হবে। এই পদ্ধতির আপনাকে কী আশা করে তা জানায় এবং তা নির্ধারণ করা একটি সচেতন সিদ্ধান্ত। বেশিরভাগ প্রোগ্রামিং ভাষার মতো, কেউ নিজেকে পায়ে গুলি করতে বাধা দেয় না। তবে আপনি এটি করছেন তা স্পষ্টভাবে ইঙ্গিত করার জন্য এটি একটি এপিআই দ্বারা সর্বদা ভাল))
মাইকেল ক্লেমেট

+1 দেখতে দুর্দান্ত এবং সাধারণ দেখাচ্ছে। তবে, আমি একটি সমস্যা দেখতে পাচ্ছি। আমার যদি অবজেক্টস থাকে a, b, c, dতবে আমি শুরু করতে পারি aএবং এটি ব্যবহার করে ইতিমধ্যে শুরু হওয়া অবজেক্ট হিসাবে MySessionব্যবহারের চেষ্টা করার চেষ্টা করা হয়েছে b, বাস্তবে এটি নেই।
ভোরাক

8

ক্যাশকো-এর উত্তর নিয়ে বিল্ডিং - কেন আপনি কলারের কাছে একটি নতুন অবজেক্ট উপস্থাপন করতে হবে, যখন আপনি কেবল একটি নতুন ইন্টারফেস উপস্থাপন করতে পারবেন? Rebrand-প্যাটার্ন:

class IStartable     { public: virtual IRunnable      start()     = 0; };
class IRunnable      { public: virtual ITerminateable run()       = 0; };
class ITerminateable { public: virtual void           terminate() = 0; };

আপনি যদি আইশরিনেটেবলকে আইআরুনেবল প্রয়োগ করতেও পারেন, যদি সেশনটি একাধিকবার চালানো যায়।

আপনার অবজেক্ট:

class Service : IStartable, IRunnable, ITerminateable
{
  public:
    IRunnable      start()     { ...; return this; }
    ITerminateable run()       { ...; return this; }
    void           terminate() { ...; }
}

// And use it like this:
IStartable myService = Service();

// Now you can only call start() via the interface
IRunnable configuredService = myService.start();

// Now you can also call run(), because it is wrapped in the new interface...

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


1
বেশ কয়েকটি পরিবর্তে কেবল একটি অন্তর্নিহিত শ্রেণি থাকার সুবিধা কী? যেহেতু আমি প্রস্তাবিত সমাধানের সাথে এটিই একমাত্র পার্থক্য, তাই আমি এই বিশেষ বিষয়টিতে আগ্রহী হব।
মাইকেল লে বারবিয়ার গ্রেনওয়াল্ড

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


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

1
@ মাইকেলগ্রিনওয়াল্ড যদি আপনি কেবলমাত্র নির্দিষ্ট ইন্টারফেসের মাধ্যমে নির্দিষ্ট একটি নির্দিষ্ট পয়েন্টের মাধ্যমে অবজেক্টটির সাথে ইন্টারঅ্যাক্ট করেন তবে সেই অবস্থায় অ্যাক্সেস করার কোনও উপায় (ingালাই ছাড়াই) থাকা উচিত নয়।
জোশুয়া টেলর

2

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

  1. বিভিন্ন রাজ্যের চিহ্নিত আপনার ডিভাইস, হতে পারে যেমন Uninitialised, Started, Configuredইত্যাদি। তালিকাটি সীমাবদ্ধ করতে হবে ¹

  2. প্রতিটি রাজ্যের জন্য, structসেই রাজ্যের সাথে সম্পর্কিত প্রয়োজনীয় অতিরিক্ত তথ্য হোল্ডিং সংজ্ঞা দিন DeviceUninitialised, DeviceStartedইত্যাদি।

  3. সমস্ত চিকিত্সা একটি সামগ্রীতে প্যাক করুন DeviceStrategyযেখানে পদ্ধতিগুলি ইনপুট এবং আউটপুট হিসাবে 2 হিসাবে সংজ্ঞায়িত স্ট্রাকচার ব্যবহার করে। সুতরাং, আপনার একটি DeviceStarted DeviceStrategy::start (DeviceUninitalised dev)পদ্ধতি থাকতে পারে (বা আপনার প্রকল্পের কনভেনশন অনুসারে সমতুল্য যাই হোক না কেন)।

এই পদ্ধতির সাথে, একটি বৈধ প্রোগ্রাম অবশ্যই পদ্ধতি প্রোটোটাইপগুলি দ্বারা প্রয়োগ করা অনুক্রমের কিছু পদ্ধতি কল করতে হবে।

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

আমি ৩. এ বর্ণিত হয়েছি এমন একটি অনন্য DeviceStrategyশ্রেণি, এমন পরিস্থিতিতে রয়েছে যেখানে আপনি বেশ কয়েকটি ক্লাস জুড়ে সরবরাহ করে এমন কার্যকারিতা বিভক্ত করতে পারেন।

তাদের সংক্ষিপ্তসার হিসাবে, আমি বর্ণিত ডিজাইনের মূল পয়েন্টগুলি হ'ল:

  1. বিকল্প নীতিমালার কারণে, ডিভাইস রাজ্যের প্রতিনিধিত্বকারী বস্তুর আলাদা হওয়া উচিত এবং বিশেষ উত্তরাধিকারের সম্পর্ক থাকা উচিত নয় have

  2. ডিভাইসগুলি নিজেরাই উপস্থাপনকারী বস্তুগুলির পরিবর্তে স্টার্টিজি অবজেক্টগুলিতে ডিভাইস চিকিত্সা প্যাক করুন, যাতে প্রতিটি ডিভাইস বা ডিভাইস রাষ্ট্র কেবল নিজেরাই দেখে এবং কৌশলটি তাদের সমস্তটি দেখে এবং তাদের মধ্যে সম্ভাব্য রূপান্তরগুলি প্রকাশ করে।

আমি শপথ করব আমি একবার এই লাইনগুলি অনুসরণ করে একটি টেলনেট ক্লায়েন্টের প্রয়োগের বিবরণ দেখেছি, তবে আমি এটি আবার খুঁজে পাচ্ছি না। এটি একটি খুব দরকারী রেফারেন্স হত!

।: এর জন্য, হয় আপনার স্বজ্ঞাততা অনুসরণ করুন বা "মেথড ~ মেথড ₂ আইএফএফের সম্পর্কের জন্য আপনার প্রকৃত বাস্তবায়নে পদ্ধতির সমতুল্য ক্লাসগুলি সন্ধান করুন। আপনার একই ডিভাইসে এটি ব্যবহার করার জন্য এটি বৈধ ”- ধরে নিলে আপনার ডিভাইসে সমস্ত চিকিত্সা আবদ্ধ করে আপনার একটি বড় অবজেক্ট রয়েছে। তালিকা রাষ্ট্রের উভয় পদ্ধতিই দুর্দান্ত ফলাফল দেয়।


1
পৃথক স্ট্রাক্ট সংজ্ঞায়িত করার পরিবর্তে, প্রতিটি পর্যায়ে একটি অবজেক্ট উপস্থিত থাকতে হবে এমন প্রয়োজনীয় ইন্টারফেসগুলি সংজ্ঞায়িত করতে যথেষ্ট হতে পারে। তারপরে এটি স্টেপ বিল্ডার প্যাটার্ন
জোশুয়া টেলর

2

একটি বিল্ডার-প্যাটার্ন ব্যবহার করুন।

আপনি উপরে উল্লিখিত সমস্ত ক্রিয়াকলাপের জন্য একটি পদ্ধতি রয়েছে যার একটি পদ্ধতি রয়েছে। তবে এটি এখনই এই ক্রিয়াকলাপগুলি সম্পাদন করে না। এটি কেবল প্রতিটি অপারেশন পরবর্তী সময়ের জন্য মনে রাখে। ক্রিয়াকলাপগুলি এখনই সম্পাদন করা হয়নি, তাই আপনি বিল্ডারের কাছে যে ক্রমটি তাদের পাঠিয়েছেন তাতে কিছু আসে যায় না।

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


1

আপনার কেবল ইন্টারফেসটি কীভাবে ব্যবহৃত হয় তা সঠিকভাবে নথী করতে হবে এবং একটি টিউটোরিয়াল উদাহরণ দিতে হবে।

আপনার একটি ডিবাগিং লাইব্রেরি বৈকল্পিকও থাকতে পারে যা কিছু রানটাইম চেক করে।

সম্ভবত সংজ্ঞা এবং সঠিকভাবে কিছু নামকরণ নিয়মাবলী দলিল (যেমন preconfigure*, startup*, postconfigure*, run*....)

বিটিডাব্লু, প্রচুর বিদ্যমান ইন্টারফেস একই ধরণের প্যাটার্ন অনুসরণ করে (যেমন এক্স 11 টুলকিটস)।


অ্যান্ড্রয়েড অ্যাপ্লিকেশন ক্রিয়াকলাপের লাইফসাইকের অনুরূপ একটি রাষ্ট্রীয় রূপান্তর চিত্রটি তথ্য জানাতে প্রয়োজন হতে পারে।
রওয়ং

1

এটি প্রকৃতপক্ষে একটি সাধারণ এবং প্রতারণামূলক ধরণের ত্রুটি, কারণ সংকলকরা কেবল সিনট্যাক্সের শর্ত প্রয়োগ করতে পারে, যখন আপনার ক্লায়েন্ট প্রোগ্রামগুলি "ব্যাকরণগতভাবে" সঠিক হওয়া দরকার।

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


তোমার মত কিছু বলতে চাইছেন না এই ?
ভোরাক

1
public class Executor {

private Executor() {} // helper class

  public void execute(MyStepsRunnable r) {
    r.step1();
    r.step2();
    r.step3();
  }
}

interface MyStepsRunnable {

  void step1();
  void step2();
  void step3();
}

এই নিদর্শনটি ব্যবহার করে আপনি নিশ্চিত যে কোনও বাস্তবায়নকারী এই সঠিক ক্রমে কার্যকর করবেন। আপনি আরও একধাপ এগিয়ে যেতে পারেন এবং একটি এক্সিকিউটারফ্যাক্টরি তৈরি করতে পারেন যা কাস্টম এক্সিকিউশন পাথ দিয়ে এক্সিকিউটারকে তৈরি করবে।


ইন অন্য মন্তব্য আপনি এই বাস্তবায়ন রচয়িতা একটি পদক্ষেপ বলা হয়, কিন্তু এটা না। আপনার যদি মাইস্টেপস রুনেবলের উদাহরণ থাকে তবে আপনি স্টেপ 1 এর আগে স্টিপ 3 কল করতে পারেন। একটি পদক্ষেপ রচয়িতা প্রয়োগের লাইন বরাবর আরো হবে ideone.com/UDECgY । স্টেপ 1 চালিয়ে এই ধারণাটি কেবল পদক্ষেপ 2 দিয়ে পাওয়া যায়। সুতরাং আপনি সঠিক ক্রমে পদ্ধতি কল করতে বাধ্য। উদাহরণস্বরূপ, স্ট্যাকওভারফ্লো . com/q/17256627/1281433 দেখুন
জোশুয়া টেলর

যেভাবে এটি ব্যবহার করা যেতে পারে তা সীমাবদ্ধ করতে আপনি সুরক্ষিত পদ্ধতিগুলি (বা এমনকি ডিফল্ট) দিয়ে এটি একটি বিমূর্ত শ্রেণিতে রূপান্তর করতে পারেন। আপনি নির্বাহককে ব্যবহার করতে বাধ্য হবেন, তবে আমার কাছে বর্তমান বাস্তবায়নে দু'একটি ত্রুটি থাকতে পারে।
সিলভিউ বুর্কিয়া

এটি এখনও এটি একটি পদক্ষেপ নির্মাতা করে না। আপনার কোডটিতে এমন কোনও কিছুই নেই যা ব্যবহারকারীর বিভিন্ন পদক্ষেপের মধ্যে কোড চালাতে পারে । ধারণা নয় শুধু (নির্বিশেষে তার সর্বজনীন বা ব্যক্তিগত, বা অন্যথায় encapsulated কিনা) ক্রম কোডে। আপনার কোড হিসাবে দেখায় যে এটি সহজভাবে করার পক্ষে যথেষ্ট সহজ step1(); step2(); step3();। পদক্ষেপ নির্মাতার বিষয়টি হ'ল এমন একটি এপিআই দেওয়া যা কিছু পদক্ষেপের বহিঃপ্রকাশ ঘটায় এবং যে সিকোয়েন্সটি তাদের ডাকা হয় তা প্রয়োগ করে। এটি কোনও প্রোগ্রামারকে পদক্ষেপের মধ্যে অন্য জিনিসগুলি করা থেকে বিরত রাখা উচিত নয়।
জোশুয়া টেলর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.