আমি কখন ভিজিটর ডিজাইন প্যাটার্ন ব্যবহার করব? [বন্ধ]


315

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

এমন একজন হিসাবে যিনি সম্প্রতি সত্যই সাজসজ্জার প্যাটার্নটি পেয়েছেন এবং এখন একেবারে সর্বত্র এর ব্যবহার দেখতে পাচ্ছেন আমি খুব সহজেই স্বতঃস্ফূর্তভাবে এই আপাতদৃষ্টিতে সহজলভ্য প্যাটার্নটি বুঝতে সক্ষম হতে চাই।


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

1
: এখানে একটা চমৎকার নিবন্ধ codeproject.com/Articles/186185/Visitor-Design-Pattern
সাঈদ Morteza মুসাভী

3
ভিজিটর প্যাটার্ন? কোনটি? কথাটি হ'ল: এই নকশার ধরণটির চারপাশে প্রচুর ভুল বোঝাবুঝি এবং খাঁটি বিভ্রান্তি রয়েছে। আমি লিখেছি এবং নিবন্ধটি যা আশাকরি এই বিশৃঙ্খলাটিকে কিছুটা অর্ডার দিয়েছে: rgomes-info.blogspot.co.uk/2013/01/…
রিচার্ড

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

এখানে এবং এখানে উদাহরণ ।
jaco0646

উত্তর:


315

আমি ভিজিটর ধাঁচের সাথে খুব বেশি পরিচিত নই। আমি ঠিক আছে কিনা তা দেখুন। মনে করুন আপনার কাছে একটি প্রাণীক্রম রয়েছে

class Animal {  };
class Dog: public Animal {  };
class Cat: public Animal {  };

(ধরুন এটি একটি সু-প্রতিষ্ঠিত ইন্টারফেস সহ একটি জটিল শ্রেণিবিন্যাস।)

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

class Animal
{ public: virtual void makeSound() = 0; };

class Dog : public Animal
{ public: void makeSound(); };

void Dog::makeSound()
{ std::cout << "woof!\n"; }

class Cat : public Animal
{ public: void makeSound(); };

void Cat::makeSound()
{ std::cout << "meow!\n"; }

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

দর্শনার্থী প্যাটার্ন আপনাকে প্রতিটি নতুন ক্রিয়াকলাপকে উপযুক্ত শ্রেণিতে স্থানান্তর করতে দেয় এবং আপনাকে স্তরক্রমের ইন্টারফেসটি একবারে বাড়ানো দরকার। চল এটা করি. প্রথমত, আমরা একটি বিমূর্ত ক্রিয়াকে সংজ্ঞায়িত করি ( জিওএফ-তে "দর্শনার্থী" শ্রেণি ) যা শ্রেণিবিন্যাসের প্রতিটি শ্রেণির জন্য একটি পদ্ধতি রয়েছে:

class Operation
{
public:
    virtual void hereIsADog(Dog *d) = 0;
    virtual void hereIsACat(Cat *c) = 0;
};

তারপরে, আমরা নতুন ক্রিয়াকলাপ গ্রহণ করার জন্য শ্রেণিবিন্যাসকে সংশোধন করি:

class Animal
{ public: virtual void letsDo(Operation *v) = 0; };

class Dog : public Animal
{ public: void letsDo(Operation *v); };

void Dog::letsDo(Operation *v)
{ v->hereIsADog(this); }

class Cat : public Animal
{ public: void letsDo(Operation *v); };

void Cat::letsDo(Operation *v)
{ v->hereIsACat(this); }

অবশেষে, আমরা ক্যাট বা কুকুর না পরিবর্তিত আসল অপারেশনটি বাস্তবায়ন করি :

class Sound : public Operation
{
public:
    void hereIsADog(Dog *d);
    void hereIsACat(Cat *c);
};

void Sound::hereIsADog(Dog *d)
{ std::cout << "woof!\n"; }

void Sound::hereIsACat(Cat *c)
{ std::cout << "meow!\n"; }

এখন আপনার হায়ারার্কি আর সংশোধন না করে অপারেশন যুক্ত করার একটি উপায় রয়েছে। এটা যেভাবে কাজ করে:

int main()
{
    Cat c;
    Sound theSound;
    c.letsDo(&theSound);
}

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

14
@ জ্ঞানসিল্যা - এটি সত্য নয়। & -Oprator সাউন্ড-অবজেক্টের ঠিকানা দেয় যা ইন্টারফেসের দ্বারা প্রয়োজনীয়। letsDo(Operation *v) একটি পয়েন্টার প্রয়োজন।
একুইলাপ্যাক্স

3
শুধু স্বচ্ছতার জন্য, দর্শনার্থীদের ডিজাইনের ধরণটির উদাহরণটি কি সঠিক?
গডজিলা

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

6
আপনার শেষে "প্রধান" উদাহরণে: theSound.hereIsACat(c)কাজটি করতে পারতেন, প্যাটার্ন দ্বারা প্রবর্তিত সমস্ত ওভারহেডের জন্য আপনি কীভাবে ন্যায়সঙ্গত হন? ডাবল প্রেরণ সমর্থনযোগ্যতা।
ফ্রান্সসু

131

আপনার বিভ্রান্তির কারণ সম্ভবতঃ ভিজিটর একটি মারাত্মক ভুল নাম omer অনেক (বিশিষ্ট 1 !) প্রোগ্রামাররা এই সমস্যায় হোঁচট খেয়েছে। এটি আসলে যা করে তা হ'ল যে ভাষাগুলি এটিকে সমর্থন করে না এমন ভাষাগুলিতে দ্বৈত প্রেরণ বাস্তবায়ন করে (তাদের বেশিরভাগই তা সমর্থন করে না)।


1) আমার প্রিয় উদাহরণ স্কট মায়ার্স, "কার্যকর সি ++" র প্রশংসিত লেখক, যাকে এটিকে তাঁর সবচেয়ে গুরুত্বপূর্ণ সি ++ আহ বলেছিলেন ! মুহূর্ত কখনও


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

@ ব্যবহারকারী3125280 আমি এখন 4/5 নিবন্ধ এবং ভিজিটর প্যাটার্নে ডিজাইন প্যাটার্নস অধ্যায়টি পড়েছি এবং তাদের কেউই এই ক্ষেত্রে অস্পষ্ট নিদর্শনটি কোনও কেস স্ট্যাম্টের মাধ্যমে ব্যবহার করার সুবিধা ব্যাখ্যা করে না, বা যখন আপনি অন্যটির উপরে ব্যবহার করতে পারেন। অন্তত এটি আনার জন্য Thx!
স্পিন্কাস

4
@sam আমি নিশ্চিত প্রশংসনীয় তারা তা ব্যাখ্যা করবেন - এটা একই সুবিধা যে আপনি সবসময় পেতে subclassing / রানটাইম পলিমরফিজম থেকে বেশি switch: switchক্লায়েন্ট সাইড (কোড অনুলিপি) এ সিদ্ধান্ত হার্ড কোড এবং স্ট্যাটিক টাইপ পরীক্ষণ অফার করে না ( কেসগুলির সম্পূর্ণতা এবং স্বতন্ত্রতার জন্য পরীক্ষা করুন) দর্শনার্থীর প্যাটার্নটি প্রকার পরীক্ষক দ্বারা যাচাই করা হয় এবং সাধারণত ক্লায়েন্ট কোডটি সহজ করে।
কনরাড রুডলফ

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

1
@ সামিপিংকস কনরাডের স্পট চালু - সেই কারণেই virtualআধুনিক প্রোগ্রামিং ভাষাগুলিতে বৈশিষ্ট্যগুলি এতটাই দরকারী - এগুলি এক্সটেনসিবল প্রোগ্রামগুলির মূল ভিত্তি ব্লক - আমার মতে সি উপায় (নেস্টেড সুইচ বা প্যাটার্ন ম্যাচ, ইত্যাদি আপনার পছন্দ অনুসারে ভাষা) কোডে অনেকটা ক্লিনার যার প্রসারিত হওয়ার দরকার নেই এবং প্রবাদ 9 এর মতো জটিল সফ্টওয়্যারটিতে এই স্টাইলটি দেখে আমি আনন্দিতভাবে অবাক হয়েছি More আরও গুরুত্বপূর্ণভাবে যে কোনও ভাষা যা এক্সটেনসিবিলিটি দিতে চায় তা সম্ভবত পুনরাবৃত্তির একক প্রেরণের চেয়ে আরও ভাল প্রেরণের নমুনাগুলির সমন্বয় করা উচিত (যেমন দর্শনার্থী).
ব্যবহারকারী3125280

84

এখানে প্রত্যেকেই সঠিক, তবে আমি মনে করি এটি "কখন" সম্বোধন করতে ব্যর্থ। প্রথমত, নকশার প্যাটার্নগুলি থেকে:

দর্শনার্থী আপনাকে যে উপাদানগুলির উপর চালিত হয় তাদের ক্লাসগুলি পরিবর্তন না করেই আপনাকে একটি নতুন ক্রিয়াকলাপ সংজ্ঞায়িত করতে দেয়।

এখন, আসুন একটি সাধারণ শ্রেণিবিন্যাসের কথা ভাবা। আমার ক্লাস 1, 2, 3 এবং 4 রয়েছে এবং এ, বি, সি এবং ডি পদ্ধতিগুলি স্প্রেডশিটের মতো এগুলি ছড়িয়ে দিন: ক্লাসগুলি লাইন এবং পদ্ধতিগুলি কলাম হয়।

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

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

যাইহোক, এটি সেই সমস্যা যা স্কেলার প্যাটার্নের সাথে মিলছে solve


আমি কেন কেবলমাত্র একটি সার্বিক ক্লাসে দর্শকের প্যাটার্নটি ব্যবহার করব। আমি আমার ইউটিলিটি ক্লাসটিকে এটির মতো কল করতে পারি: অ্যানালিটিক্স ম্যানজার.ভিসিট (সামান্য অবজেক্টটোভিট) বনাম অ্যানালিটিক্সভিসিটার.ভিসিট (কিছুটা ওজেক্টটওভিট)। পার্থক্য কি? তারা উভয়ই উদ্বেগের বিচ্ছেদ সঠিক? আপনি সাহায্য করতে পারেন আশা করি।
j2emanue

@ j2emanue কারণ ভিজিটর প্যাটার্নটি রানটাইমে সঠিক ভিজিটরের ওভারলোড ব্যবহার করে। আপনার কোডের সঠিক ওভারলোডকে কল করার জন্য টাইপ কাস্টিংয়ের প্রয়োজন রয়েছে।
অ্যাক্সেস অস্বীকার

এর সাথে কোনও দক্ষতা লাভ আছে? আমার ধারণা এটি এটির একটি ভাল ধারণা
ingালাই

@ j2emanue ধারণাটি কোড লিখতে হবে যা খোলার / বন্ধ নীতি অনুসারে কাজ করে, পারফরম্যান্সের কারণে নয়। খোলা চাচা বব বন্ধ দেখুন butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
অ্যাক্সেস অস্বীকৃত

22

ভিজিটর নকশা প্যাটার্ন ডিরেক্টরির গাছ, এক্সএমএল কাঠামো, বা নথির প্রান্তরেখা মত "রিকার্সিভ" স্ট্রাকচার জন্য সত্যিই ভাল কাজ করে।

একটি দর্শনার্থী অবজেক্ট পুনরাবৃত্তাকার কাঠামোর প্রতিটি নোড পরিদর্শন করে: প্রতিটি ডিরেক্টরি, প্রতিটি এক্সএমএল ট্যাগ, যাই হোক না কেন। ভিজিটর অবজেক্ট কাঠামোর মধ্য দিয়ে লুপ হয় না। পরিবর্তে কাঠামোর প্রতিটি নোডে ভিজিটর পদ্ধতি প্রয়োগ করা হয়।

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

class TreeNode( object ):
    def __init__( self, name, *children ):
        self.name= name
        self.children= children
    def visit( self, someVisitor ):
        someVisitor.arrivedAt( self )
        someVisitor.down()
        for c in self.children:
            c.visit( someVisitor )
        someVisitor.up()

visitপদ্ধতি গঠন প্রতিটি নোডের একটি ভিজিটর বস্তুর ক্ষেত্রে প্রযোজ্য। এই ক্ষেত্রে, এটি শীর্ষ-দর্শনার্থী। আপনি visitনীচের অংশে বা অন্য কোনও অর্ডার করার জন্য পদ্ধতির কাঠামো পরিবর্তন করতে পারেন ।

এখানে দর্শকদের জন্য একটি সুপারক্লাস। এটি visitপদ্ধতি দ্বারা ব্যবহৃত হয় । এটি কাঠামোর প্রতিটি নোড "পৌঁছে"। যেহেতু visitপদ্ধতিটি কল করে upএবং downতাই দর্শক গভীরতার উপর নজর রাখতে পারে।

class Visitor( object ):
    def __init__( self ):
        self.depth= 0
    def down( self ):
        self.depth += 1
    def up( self ):
        self.depth -= 1
    def arrivedAt( self, aTreeNode ):
        print self.depth, aTreeNode.name

একটি সাবক্লাস প্রতিটি স্তরে গণনা নোডের মতো কাজ করতে পারে এবং নোডের একটি তালিকা জোগাড় করে একটি দুর্দান্ত পথের শ্রেণিবদ্ধ বিভাগ সংখ্যা তৈরি করতে পারে।

এখানে একটি আবেদন। এটি একটি গাছ কাঠামো তৈরি করে someTree,। এটা একটা সৃষ্টি Visitor, dumpNodes

তারপরে এটি dumpNodesগাছের ক্ষেত্রে প্রযোজ্য । dumpNodeবস্তুর গাছ প্রতিটি নোডের "যান" হবে।

someTree= TreeNode( "Top", TreeNode("c1"), TreeNode("c2"), TreeNode("c3") )
dumpNodes= Visitor()
someTree.visit( dumpNodes )

ট্রিনোড visitঅ্যালগরিদম নিশ্চয়তা দেবে যে প্রতিটি ট্রিনোড ভিজিটর arrivedAtপদ্ধতির পক্ষে যুক্তি হিসাবে ব্যবহৃত হয় ।


8
অন্যরা যেমন বলেছে যে এটি "শ্রেণিবিন্যাসের দর্শনের ধরণ"।
পিপিসি কোডার

1
@ পিপিসি-কোডার 'শ্রেণিবদ্ধ দর্শনের ধরণ' এবং দর্শনার্থীর প্যাটার্নের মধ্যে পার্থক্য কী?
টিম লাভল-স্মিথ

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

18

এটি দেখার একটি উপায় হ'ল ভিজিটর প্যাটার্ন হ'ল এক উপায় যা আপনার ক্লায়েন্টদের একটি নির্দিষ্ট শ্রেণীর শ্রেণিবিন্যাসে আপনার সমস্ত ক্লাসে অতিরিক্ত পদ্ধতি যুক্ত করতে দেয়।

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

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

দর্শনার্থী প্যাটার্ন ব্যতীত, প্রতিবার কোনও বিকাশকারী কোনও নতুন বৈশিষ্ট্য যুক্ত করতে চেয়েছিলেন, তাদের বেস শ্রেণীর প্রতিটি বৈশিষ্ট্যে এই পদ্ধতিটি যুক্ত করা দরকার। এটি বিশেষত কঠিন যখন বেস ক্লাসগুলি একটি পৃথক গ্রন্থাগারে প্রদর্শিত হয় বা একটি পৃথক দল দ্বারা উত্পাদিত হয়।

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


আমি নিম্নলিখিতটিতে আপনার মতামতটিও চাই: আমি কেন কেবলমাত্র সর্বোত্তম শ্রেণীর উপর দর্শনার্থীর প্যাটার্নটি ব্যবহার করব। আমি আমার ইউটিলিটি ক্লাসটিকে এটির মতো কল করতে পারি: অ্যানালিটিক্স ম্যানজার.ভিসিট (সামান্য অবজেক্টটোভিট) বনাম অ্যানালিটিক্সভিসিটার.ভিসিট (কিছুটা ওজেক্টটওভিট)। পার্থক্য কি? তারা উভয়ই উদ্বেগের বিচ্ছেদ সঠিক? আপনি সাহায্য করতে পারেন আশা করি।
j2emanue

@ j2emanue: আমি প্রশ্নটি বুঝতে পারি না। আমি আপনাকে এটির পরামর্শ দিয়েছি এবং উত্তর দেওয়ার জন্য এটি একটি সম্পূর্ণ প্রশ্ন হিসাবে পোস্ট করুন।
14-18 এ অদ্ভুত ধারণা

1
: আমি এখানে একটি নতুন প্রশ্ন পোস্ট stackoverflow.com/questions/52068876/...
j2emanue

14

ভিজিটর প্যাটার্নটি ব্যবহারের জন্য কমপক্ষে তিনটি খুব ভাল কারণ রয়েছে:

  1. কোডের বিস্তার হ্রাস করুন যা ডেটা স্ট্রাকচার পরিবর্তিত হয় তখন কিছুটা আলাদা different

  2. কোডটি পরিবর্তন না করেই গণনা প্রয়োগ করে বেশ কয়েকটি ডেটা স্ট্রাকচারে একই গণনা প্রয়োগ করুন।

  3. উত্তরাধিকারের কোডটি পরিবর্তন না করেই উত্তরাধিকার লাইব্রেরিতে তথ্য যুক্ত করুন।

আমি এই সম্পর্কে লিখেছি নিবন্ধটি একবার দেখুন ।


1
আমি আপনার নিবন্ধটিতে দর্শকদের জন্য দেখেছি এমন একক বৃহত্তম ব্যবহারের সাথে মন্তব্য করেছি। থটস?
জর্জ মাউয়ার

13

কনরাদ রুডল্ফ যেমন ইতিমধ্যে উল্লেখ করেছেন, এটি আমাদের প্রয়োজন যেখানে ক্ষেত্রে উপযুক্ত ডাবল প্রেরণের

আমাদের এমন একটি পরিস্থিতি প্রদর্শনের একটি উদাহরণ দেওয়া হল যেখানে আমাদের ডাবল প্রেরণের প্রয়োজন হয় এবং দর্শক এটি কীভাবে আমাদের সহায়তা করে।

উদাহরণ:

বলুন আমার কাছে 3 ধরণের মোবাইল ডিভাইস রয়েছে - আইফোন, অ্যান্ড্রয়েড, উইন্ডোজ মোবাইল।

এই তিনটি ডিভাইসে একটি ব্লুটুথ রেডিও ইনস্টল করা আছে।

ধরে নেওয়া যাক যে নীল দাঁত রেডিওটি 2 পৃথক OEM- ইন্টেল এবং ব্রডকম থেকে হতে পারে।

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

আমার ক্লাসগুলি এইভাবে দেখায় -

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

এখন, আমি একটি অপারেশন - মোবাইল ডিভাইসে ব্লুটুথ স্যুইচিং চালু করতে চাই।

এর ফাংশনের স্বাক্ষর এর মতো কিছু পছন্দ করা উচিত -

 void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)

সুতরাং ডান ধরণের ডিভাইসের উপর নির্ভর করে এবং সঠিক ধরণের ব্লুটুথ রেডিওর উপর নির্ভর করে উপযুক্ত পদক্ষেপ বা অ্যালগরিদম কল করে এটি চালু করা যেতে পারে

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

উভয় যুক্তির ধরণের উপর নির্ভর করে একটি পলিমারফিক আচরণ।

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

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

3x2 ম্যাট্রিক্সের কারণে ডাবল প্রেরণ এখানে প্রয়োজনীয়

সেটআপটি দেখতে কেমন হবে তা এখানে - এখানে চিত্র বর্ণনা লিখুন

আমি অন্য প্রশ্নের উত্তর দেওয়ার জন্য উদাহরণটি লিখেছি, কোড এবং এর ব্যাখ্যা এখানে উল্লেখ করা হয়েছে


9

নিম্নলিখিত লিঙ্কগুলিতে আমি এটি আরও সহজ পেয়েছি:

ইন http://www.remondo.net/visitor-pattern-example-csharp/ আমি একটি উদাহরণ দেখা গেছে যে শো একটি উপহাস উদাহরণ পরিদর্শক প্যাটার্ন লাভ কি দেখায়। এখানে আপনার জন্য বিভিন্ন ধারক ক্লাস রয়েছে Pill:

namespace DesignPatterns
{
    public class BlisterPack
    {
        // Pairs so x2
        public int TabletPairs { get; set; }
    }

    public class Bottle
    {
        // Unsigned
        public uint Items { get; set; }
    }

    public class Jar
    {
        // Signed
        public int Pieces { get; set; }
    }
}

আপনি উপরের হিসাবে দেখতে পাচ্ছেন, আপনার BilsterPackজোড়া জোড়া রয়েছে যাতে আপনার জোড়ের সংখ্যা 2 দিয়ে গুণতে হয় Also এছাড়াও আপনি খেয়াল করতে পারেন যে Bottleব্যবহারটি unitবিভিন্ন ডেটাটাইপ এবং beালাই করা দরকার।

সুতরাং প্রধান পদ্ধতিতে আপনি নিম্নলিখিত কোড ব্যবহার করে পিল গণনা গণনা করতে পারেন:

foreach (var item in packageList)
{
    if (item.GetType() == typeof (BlisterPack))
    {
        pillCount += ((BlisterPack) item).TabletPairs * 2;
    }
    else if (item.GetType() == typeof (Bottle))
    {
        pillCount += (int) ((Bottle) item).Items;
    }
    else if (item.GetType() == typeof (Jar))
    {
        pillCount += ((Jar) item).Pieces;
    }
}

লক্ষ্য করুন যে উপরের কোডটি লঙ্ঘন করেছে Single Responsibility Principle। এর অর্থ আপনি যদি নতুন ধরণের ধারক যুক্ত করেন তবে আপনাকে অবশ্যই মূল পদ্ধতি কোডটি পরিবর্তন করতে হবে। এছাড়াও দীর্ঘ সময় স্যুইচ করা খারাপ অভ্যাস।

সুতরাং নিম্নলিখিত কোড প্রবর্তন করে:

public class PillCountVisitor : IVisitor
{
    public int Count { get; private set; }

    #region IVisitor Members

    public void Visit(BlisterPack blisterPack)
    {
        Count += blisterPack.TabletPairs * 2;
    }

    public void Visit(Bottle bottle)
    {
        Count += (int)bottle.Items;
    }

    public void Visit(Jar jar)
    {
        Count += jar.Pieces;
    }

    #endregion
}

আপনি Pillক্লাস নাম্বার গণনার দায়িত্ব PillCountVisitorসরিয়ে নিয়েছেন (এবং আমরা স্যুইচ কেস স্টেটমেন্ট সরিয়ে দিয়েছি)। এর অর্থ যখনই আপনাকে নতুন ধরণের পিল পাত্রে যুক্ত করতে হবে আপনার কেবল PillCountVisitorশ্রেণি পরিবর্তন করা উচিত । এছাড়াও নোটিশ IVisitorইন্টারফেস অন্য পরিস্থিতিতে ব্যবহার করার জন্য সাধারণ।

কন্টেইনার ক্লাসে পিসি গ্রহণ পদ্ধতি যুক্ত করে:

public class BlisterPack : IAcceptor
{
    public int TabletPairs { get; set; }

    #region IAcceptor Members

    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }

    #endregion
}

আমরা ভিজিটরকে পিল কনটেইনার ক্লাস ঘুরে দেখার অনুমতি দিই।

শেষে আমরা নীচের কোড ব্যবহার করে পিল গণনা গণনা করি:

var visitor = new PillCountVisitor();

foreach (IAcceptor item in packageList)
{
    item.Accept(visitor);
}

এর অর্থ হ'ল: প্রতিটি পিল পাত্রে PillCountVisitorদর্শনার্থীদের তাদের বড়ি গণনা দেখতে দেয়। তিনি জানেন যে কীভাবে আপনার বড়ি গুনতে হয়।

visitor.Countবড়িগুলির মূল্য রয়েছে।

Http://butunclebob.com/ArticleS.Uncleलय . IuseVisitor এ আপনি এমন বাস্তব দৃশ্য দেখতে পাবেন যেখানে আপনি একক দায়িত্বের নীতি অনুসরণ করতে পলিমারফিজম (উত্তর) ব্যবহার করতে পারবেন না । বাস্তবে:

public class HourlyEmployee extends Employee {
  public String reportQtdHoursAndPay() {
    //generate the line for this hourly employee
  }
}

reportQtdHoursAndPayপদ্ধতি প্রতিবেদন এবং উপস্থাপনা জন্য এবং এই একক দায়িত্ব নীতি লঙ্ঘন করে। সুতরাং সমস্যাটি কাটিয়ে উঠতে দর্শনার্থীদের ধরণটি ব্যবহার করা ভাল।


2
হাই সাedদ, আপনি যে অংশটি সর্বাধিক আলোকসজ্জা পেয়েছেন তা যোগ করতে দয়া করে আপনার উত্তরটি সম্পাদনা করতে পারেন? তাই সাধারণত লিঙ্ক-কেবল উত্তরগুলিকে নিরুৎসাহিত করে যেহেতু লক্ষ্য হ'ল জ্ঞান ডাটাবেস এবং লিঙ্কগুলি হ্রাস পায়।
জর্জ মাউর

8

ডাবল প্রেরণ ঠিক এই প্যাটার্নটি ব্যবহারের জন্য অন্যদের মধ্যে একটি কারণ
তবে মনে রাখবেন যে ভাষাগুলিতে একক প্রেরণের দৃষ্টান্ত ব্যবহার করে দ্বিগুণ বা অধিক প্রেরণের প্রয়োগের একক উপায় এটি।

প্যাটার্নটি ব্যবহার করার কারণ এখানে রয়েছে:

1) আমরা প্রতিটি সময়ে মডেলটি পরিবর্তন না করেই নতুন ক্রিয়াকলাপ সংজ্ঞায়িত করতে চাই কারণ মডেলটি প্রায়শই বদলে যায় না ile

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

৩) আমাদের প্রচলিত ক্রিয়াকলাপ রয়েছে যা মডেলের কংক্রিট ধরণের উপর নির্ভর করে তবে আমরা প্রতিটি সাবক্লাসে যুক্তি প্রয়োগ করতে চাই না কারণ এটি একাধিক ক্লাসে সাধারণ যুক্তিকে বিস্ফোরিত করবে এবং একাধিক জায়গায়

4) আমরা একই ডোমেন্দ্রীর একটি ডোমেন মডেল ডিজাইন এবং মডেল ক্লাস ব্যবহার করছি অনেকগুলি স্বতন্ত্র জিনিস সম্পাদন করি যা অন্য কোথাও জড়ো হতে পারে

5) আমাদের একটি ডাবল প্রেরণ প্রয়োজন
আমাদের ইন্টারফেসের ধরণের সাথে ভেরিয়েবলগুলি ঘোষিত রয়েছে এবং আমরা তাদের রানটাইমের ধরণ অনুযায়ী অবশ্যই প্রক্রিয়া করতে সক্ষম হতে চাই ... অবশ্যই ব্যবহার if (myObj instanceof Foo) {}বা কোনও কৌশল ছাড়াই ।
উদাহরণস্বরূপ ধারণাটি হল এই ভেরিয়েবলগুলিকে এমন পদ্ধতিগুলিতে পাস করা যা একটি নির্দিষ্ট প্রক্রিয়াজাতকরণ প্রয়োগের জন্য ইন্টারফেসের একটি কংক্রিট ধরণের পরামিতি হিসাবে ঘোষণা করে। ভাষাগুলির সাথে বাক্সের বাইরে এই পদ্ধতিটি একক প্রেরণের উপর নির্ভর করে কারণ রানটাইমগুলিতে নির্বাচিত নির্বাচিতগুলি কেবলমাত্র রিসিভারের রানটাইম ধরণের উপর নির্ভর করে।
নোট করুন যে জাভাতে, কল করার পদ্ধতি (স্বাক্ষর) সংকলনের সময় চয়ন করা হয়েছে এবং এটি পরামিতিগুলির ঘোষিত ধরণের উপর নির্ভর করে, তাদের রানটাইম টাইপের নয়।

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

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


জাভা উদাহরণ

আমি দাবা উদাহরণের সাথে প্যাটার্নটির যুক্ত হওয়া মূল্য চিত্রিত করব যেখানে আমরা খেলোয়াড়কে টুকরো টুকরো করার অনুরোধ করায় আমরা প্রক্রিয়াকরণটিকে সংজ্ঞায়িত করতে চাই।

দর্শনার্থীর প্যাটার্ন ব্যবহার ছাড়াই আমরা টুকরো চলমান আচরণগুলি সরাসরি টুকরো সাবক্লাসে সংজ্ঞায়িত করতে পারি।
আমরা উদাহরণস্বরূপ একটি Pieceইন্টারফেস থাকতে পারে যেমন:

public interface Piece{

    boolean checkMoveValidity(Coordinates coord);

    void performMove(Coordinates coord);

    Piece computeIfKingCheck();

}

প্রতিটি পিস সাবক্লাস এটিকে বাস্তবায়ন করবে যেমন:

public class Pawn implements Piece{

    @Override
    public boolean checkMoveValidity(Coordinates coord) {
        ...
    }

    @Override
    public void performMove(Coordinates coord) {
        ...
    }

    @Override
    public Piece computeIfKingCheck() {
        ...
    }

}

এবং সমস্ত পিস সাবক্লাস জন্য একই জিনিস।
এখানে একটি চিত্র চিত্র রয়েছে যা এই নকশাকে চিত্রিত করে:

[মডেল বর্গ ডায়াগ্রাম

এই পদ্ধতির মধ্যে তিনটি গুরুত্বপূর্ণ ত্রুটি রয়েছে:

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

- প্রসেসিং checkMoveValidity()এমন কিছু হওয়া উচিত নয় যা Pieceসাবক্লাসগুলি দেখতে বা পরিবর্তন করতে পারে।
এটি চেক যা মানব বা কম্পিউটারের ক্রিয়া ছাড়িয়ে যায়। এই চেকটি কোনও খেলোয়াড় দ্বারা অনুরোধ করা টুকরা সরানো বৈধ কিনা তা নিশ্চিত করার জন্য প্রতিটি ক্রিয়াতে সঞ্চালিত হয়।
সুতরাং আমরা এমনকি এটি সরবরাহ করতে চাই নাPiece ইন্টারফেসে ।

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

সুতরাং আসুন ভিজিটর প্যাটার্ন ব্যবহার করতে যাই!

আমাদের দুটি ধরণের কাঠামো রয়েছে:

- মডেল ক্লাসগুলি পরিদর্শন করতে স্বীকার করে (টুকরা)

- যে দর্শনার্থীরা তাদের সাথে যান (চলমান ক্রিয়াকলাপ)

এখানে একটি শ্রেণীর চিত্র রয়েছে যা প্যাটার্নটি চিত্রিত করে:

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

উপরের অংশে আমাদের কাছে দর্শক রয়েছে এবং নীচের অংশে আমাদের রয়েছে মডেল ক্লাসগুলি।

এখানে PieceMovingVisitorইন্টারফেস (প্রতিটি ধরণের জন্য নির্দিষ্ট আচরণ Piece):

public interface PieceMovingVisitor {

    void visitPawn(Pawn pawn);

    void visitKing(King king);

    void visitQueen(Queen queen);

    void visitKnight(Knight knight);

    void visitRook(Rook rook);

    void visitBishop(Bishop bishop);

}

পিসটি এখন সংজ্ঞায়িত করা হয়েছে:

public interface Piece {

    void accept(PieceMovingVisitor pieceVisitor);

    Coordinates getCoordinates();

    void setCoordinates(Coordinates coordinates);

}

এর মূল পদ্ধতিটি হ'ল:

void accept(PieceMovingVisitor pieceVisitor);

এটি প্রথম প্রেরণ সরবরাহ করে: Pieceরিসিভারের ভিত্তিতে একটি অনুরোধ ।
সংকলনের সময়, পদ্ধতিটি accept()পিস ইন্টারফেসের পদ্ধতির সাথে আবদ্ধ এবং রানটাইমে, সীমাবদ্ধ পদ্ধতিটি রানটাইম Pieceক্লাসে ডাকা হবে ।
এবং এটি সেই accept()পদ্ধতি বাস্তবায়ন যা দ্বিতীয় প্রেরণ সম্পাদন করবে।

প্রকৃতপক্ষে, প্রতিটি Pieceউপক্লাস যা কোনও PieceMovingVisitorবস্তুর দ্বারা পরিদর্শন করতে চায় সেগুলি তত্ক্ষণাত যুক্ত হয়ে PieceMovingVisitor.visit()পদ্ধতিটি আহ্বান করে।
এইভাবে, সংকলনের সময়টি সংকলনের সময়ের সাথে সাথেই সীমাবদ্ধ হয়, কংক্রিটের ধরণের সাথে ঘোষিত প্যারামিটারের ধরণ।
দ্বিতীয় প্রেরণ আছে।
এখানে Bishopসাবক্লাসটি চিত্রিত করে যে:

public class Bishop implements Piece {

    private Coordinates coord;

    public Bishop(Coordinates coord) {
        super(coord);
    }

    @Override
    public void accept(PieceMovingVisitor pieceVisitor) {
        pieceVisitor.visitBishop(this);
    }

    @Override
    public Coordinates getCoordinates() {
        return coordinates;
    }

   @Override
    public void setCoordinates(Coordinates coordinates) {
        this.coordinates = coordinates;
   }

}

এবং এখানে একটি ব্যবহারের উদাহরণ:

// 1. Player requests a move for a specific piece
Piece piece = selectPiece();
Coordinates coord = selectCoordinates();

// 2. We check with MoveCheckingVisitor that the request is valid
final MoveCheckingVisitor moveCheckingVisitor = new MoveCheckingVisitor(coord);
piece.accept(moveCheckingVisitor);

// 3. If the move is valid, MovePerformingVisitor performs the move
if (moveCheckingVisitor.isValid()) {
    piece.accept(new MovePerformingVisitor(coord));
}

দর্শনার্থীর কমতি

দর্শনার্থী প্যাটার্নটি একটি খুব শক্তিশালী নিদর্শন তবে এর কিছু গুরুত্বপূর্ণ সীমাবদ্ধতা রয়েছে যা এটি ব্যবহার করার আগে আপনার বিবেচনা করা উচিত।

1) এনক্যাপসুলেশন হ্রাস / বিচ্ছিন্ন করার ঝুঁকি

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

উদাহরণস্বরূপ, MovePerformingVisitor ক্লাসটি প্রকৃত টুকরোটির স্থানাঙ্কগুলি সেট করা দরকার হিসাবে , Pieceইন্টারফেসটিকে এটি করার একটি উপায় প্রদান করতে হবে:

void setCoordinates(Coordinates coordinates);

Pieceস্থানাঙ্ক পরিবর্তনের দায়িত্ব এখন Pieceসাবক্লাসের চেয়ে অন্য শ্রেণীর জন্য উন্মুক্ত । উপশ্রেণীতে
দর্শনার্থীর দ্বারা সম্পাদিত প্রসেসিং সরানো Pieceকোনও বিকল্প নয়।
এটি প্রকৃতপক্ষে অন্য কোনও সমস্যা তৈরি করবে কারণ Piece.accept()যে কোনও দর্শনার্থীর বাস্তবায়ন গ্রহণযোগ্য। এটি জানেন না যে দর্শক কী সম্পাদন করে এবং তাই পিসের স্থিতিটি কীভাবে পরিবর্তন করা যায় সে সম্পর্কে কোনও ধারণা নেই।
দর্শনার্থী শনাক্ত করার একটি উপায় হ'ল Piece.accept()ভিজিটর বাস্তবায়ন অনুযায়ী পোস্ট প্রসেসিং করা । এটি খুব খারাপ ধারণা হবে কারণ এটি ভিজিটর বাস্তবায়ন এবং পিস সাবক্লাসগুলির মধ্যে একটি উচ্চ সংযোগ তৈরি করবে এবং এর পাশাপাশি এটি সম্ভবত ট্রিক ব্যবহার করা প্রয়োজন getClass(), instanceofঅথবা যে কোনও মার্কেটর ভিজিটর বাস্তবায়ন চিহ্নিত করে।

2) মডেল পরিবর্তন করার প্রয়োজনীয়তা

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

accept()

3) নির্দেশাবলী

প্যাটার্নটি বহুগুণ অন্তর্নির্দেশ তৈরি করে।
ডাবল প্রেরণের অর্থ এককটির পরিবর্তে দুটি আমন্ত্রণ:

call the visited (piece) -> that calls the visitor (pieceMovingVisitor)

এবং আমাদের অতিরিক্ত নির্দেশনা থাকতে পারে কারণ ভিজিটর পরিদর্শন করা অবজেক্টের স্থিতি পরিবর্তন করে।
এটি একটি চক্রের মতো দেখাচ্ছে:

call the visited (piece) -> that calls the visitor (pieceMovingVisitor) -> that calls the visited (piece)

6

কে হোরস্টম্যান তার ওও ডিজাইন এবং নিদর্শন বইয়ে কোথায় ভিজিটর প্রয়োগ করবেন তার দুর্দান্ত উদাহরণ রয়েছে । তিনি সমস্যার সংক্ষিপ্তসার:

যৌগিক অবজেক্টগুলির প্রায়শই পৃথক উপাদানগুলির সমন্বয়ে একটি জটিল কাঠামো থাকে। কিছু উপাদান আবার শিশু উপাদান থাকতে পারে। ... একটি উপাদানের একটি ক্রিয়াকলাপটি তার শিশু উপাদানগুলিতে পরিদর্শন করে, তাদের কাছে অপারেশন প্রয়োগ করে এবং ফলাফলগুলি একত্রিত করে। ... তবে এই জাতীয় নকশায় নতুন ক্রিয়াকলাপ যুক্ত করা সহজ নয়।

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

ফাইলসিস্টেম শ্রেণীর ডায়াগ্রাম

এই কাঠামোর সাহায্যে আমরা প্রয়োগ করতে পারি এমন কিছু ক্রিয়াকলাপ (কার্যকারিতা) এখানে রয়েছে:

  • নোড উপাদানগুলির নাম প্রদর্শন করুন (একটি ফাইল তালিকা)
  • নোড উপাদানগুলির আকার গণনা করুন (যেখানে কোনও ডিরেক্টরিতে এটির সমস্ত শিশু উপাদানগুলির আকার অন্তর্ভুক্ত থাকে)
  • প্রভৃতি

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

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

ভিজিটর আমাদের FileSystemNodesনিজেরাই ডেটা স্ট্রাকচার থেকে ডেটা স্ট্রাকচারের (যেমন, ) কার্যকারিতা ডিকুয়াল করতে দেয় to প্যাটার্নটি নকশাকে সংহতি সম্মানের অনুমতি দেয় - ডেটা স্ট্রাকচার ক্লাসগুলি সহজ (তাদের কম পদ্ধতি রয়েছে) এবং কার্যকরীতাগুলি Visitorবাস্তবায়নে আবদ্ধ হয় । এটি ডাবল-প্রেরণ (যা প্যাটার্নের জটিল অংশ) এর মাধ্যমে করা হয়: accept()কাঠামো শ্রেণিতে visitX()পদ্ধতি এবং ভিজিটর (কার্যকারিতা) শ্রেণিতে পদ্ধতি ব্যবহার করে :

দর্শনার্থীর সাথে ফাইল-সিস্টেম শ্রেণীর ডায়াগ্রাম প্রয়োগ করা হয়েছে

এই কাঠামোটি আমাদের নতুন কার্যকারিতা যুক্ত করতে দেয় যা কাঠামোতে কংক্রিট ভিজিটর (কাঠামোর শ্রেণি পরিবর্তন না করে) হিসাবে কাঠামোর উপরে কাজ করে।

দর্শনার্থীর সাথে ফাইল-সিস্টেম শ্রেণীর ডায়াগ্রাম প্রয়োগ করা হয়েছে

উদাহরণস্বরূপ, একটি PrintNameVisitorযা ডিরেক্টরি তালিকা কার্যকারিতা PrintSizeVisitorকার্যকর করে এবং একটি যা আকার সহ সংস্করণটি কার্যকর করে। আমরা একদিন 'এক্সপোর্টএক্সএমএলভিসিটার'-এর এক্সএমএলে ডেটা তৈরি করতে, বা অন্য কোনও দর্শক যা এটি জেএসএন-এ তৈরি করে তা কল্পনা করতে পারি etc. আমাদের এমনকি এমন একটি দর্শনার্থীও থাকতে পারে যা আমার ডিরেক্টরি গাছটিকে যেমন ডট এর মতো গ্রাফিক্যাল ভাষা ব্যবহার করে প্রদর্শন করে , অন্য প্রোগ্রাম সহ।

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


আমার মনে হয় ডিরেক্টরি কাঠামোটি একটি ভাল সংমিশ্রিত প্যাটার্ন তবে আপনার শেষ অনুচ্ছেদে সম্মত।
জার

5

আমার মতে, নতুন অপারেশন যুক্ত করার পরিমাণের পরিমাণ Visitor Patternপ্রতিটি উপাদান কাঠামোর ব্যবহার বা সরাসরি পরিবর্তনের মাধ্যমে কম বেশি একই হয় । এছাড়াও, যদি আমি নতুন উপাদান শ্রেণি যুক্ত করতে চাই Cow, অপারেশন ইন্টারফেসটি প্রভাবিত হবে এবং এটি বিদ্যমান বিদ্যমান সমস্ত উপাদানগুলিতে প্রচার করে, সুতরাং সমস্ত উপাদান শ্রেণীর পুনঃসংশোধনের প্রয়োজন। তাহলে কথাটা কী?


4
আপনি যখন কোনও বস্তুর শ্রেণিবিন্যাসকে অনুসরণ করে কাজ করছেন তখন প্রায় প্রতিটি সময়ই আমি ভিজিটর ব্যবহার করি। নেস্টেড ট্রি মেনু বিবেচনা করুন। আপনি সমস্ত নোড ভেঙে ফেলতে চান। আপনি যদি ভিজিটর বাস্তবায়ন না করেন তবে আপনাকে গ্রাফ ট্র্যাভারসাল কোড লিখতে হবে। অথবা পরিদর্শক সঙ্গে rootElement.visit (node) -> node.collapse()। দর্শনার্থীর সাথে, প্রতিটি নোড তার সমস্ত শিশুদের জন্য গ্রাফ ট্র্যাভারসাল প্রয়োগ করে যাতে আপনি শেষ হয়ে যান।
জর্জ মাউয়ার

@ জর্জমৌয়ার, দ্বৈত প্রেরণের ধারণাটি আমার জন্য অনুপ্রেরণা পরিষ্কার করেছে: টাইপ নির্ভর নির্ভর যুক্তিটি হয় টাইপের সাথে বা ব্যথার জগতে। ট্র্যাভার্সাল লজিক বিতরণের ধারণাটি এখনও আমাকে বিরতি দেয়। এটা আরও দক্ষ? এটা কি আরও রক্ষণাবেক্ষণযোগ্য? যদি প্রয়োজন হিসাবে "ভাঁজ থেকে স্তর স্তর" যোগ করা হয় তবে কী হবে?
nik.shornikov

@ নিক.শর্নিকভ দক্ষতা এখানে সত্যই উদ্বেগের বিষয় হওয়া উচিত নয়। প্রায় কোনও ভাষায়, কয়েকটি ফাংশন কলগুলি ওভারহেডের তুলনায় নগণ্য। এর বাইরে যে কোনও কিছুই হ'ল মাইক্রো-অপ্টিমাইজেশন। এটা কি আরও রক্ষণাবেক্ষণযোগ্য? ঠিক আছে, এটা নির্ভর করে। আমার মনে হয় বেশিরভাগ সময় এটি হয়, কখনও কখনও তা হয় না। হিসাবে "স্তর থেকে স্তর এন" ভাঁজ। levelsRemainingপ্যারামিটার হিসাবে একটি কাউন্টারে সহজ পাস । শিশুদের পরবর্তী স্তরের কল করার আগে এটি হ্রাস করুন। আপনার দর্শনার্থীর ভিতরে if(levelsRemaining == 0) return
জর্জ মাউয়ার

1
@ জর্জেমাউয়ার, দক্ষতার একটি সামান্য উদ্বেগ হিসাবে সম্পূর্ণরূপে একমত। তবে রক্ষণাবেক্ষণযোগ্যতা, যেমন স্বাক্ষরকারী স্বাক্ষরের ওভাররাইডগুলি হ'ল সিদ্ধান্তটি ঠিক তেমন ফোটানো উচিত বলে আমি মনে করি।
nik.shornikov

5

অ্যাসপেক্ট অবজেক্ট প্রোগ্রামিংয়ের একই ভূগর্ভস্থ বাস্তবায়ন হিসাবে দর্শকের প্যাটার্ন ..

উদাহরণস্বরূপ, যদি আপনি এটিতে চালিত উপাদানগুলির শ্রেণি পরিবর্তন না করে কোনও নতুন অপারেশন সংজ্ঞায়িত করেন


অ্যাসপেক্ট অবজেক্ট প্রোগ্রামিং উল্লেখ করার জন্য আপ
মাইলমা 18

5

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

আপনি যখন এটি ব্যবহার বিবেচনা করতে পারেন

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

4

আমি এই প্যাটার্নটি বুঝতে পারি না যতক্ষণ না আমি মামার বব নিবন্ধটি নিয়ে এসেছি এবং মন্তব্যগুলি পড়েছি। নিম্নলিখিত কোড বিবেচনা করুন:

public class Employee
{
}

public class SalariedEmployee : Employee
{
}

public class HourlyEmployee : Employee
{
}

public class QtdHoursAndPayReport
{
    public void PrintReport()
    {
        var employees = new List<Employee>
        {
            new SalariedEmployee(),
            new HourlyEmployee()
        };
        foreach (Employee e in employees)
        {
            if (e is HourlyEmployee he)
                PrintReportLine(he);
            if (e is SalariedEmployee se)
                PrintReportLine(se);
        }
    }

    public void PrintReportLine(HourlyEmployee he)
    {
        System.Diagnostics.Debug.WriteLine("hours");
    }
    public void PrintReportLine(SalariedEmployee se)
    {
        System.Diagnostics.Debug.WriteLine("fix");
    }
}

class Program
{
    static void Main(string[] args)
    {
        new QtdHoursAndPayReport().PrintReport();
    }
}

যদিও এটি দেখতে একদম ভাল লাগতে পারে কারণ এটি একক দায়বদ্ধতার বিষয়টি নিশ্চিত করে এটি মুক্ত / বন্ধ নীতি লঙ্ঘন করে । প্রতিবার আপনার কাছে নতুন কর্মচারী টাইপ থাকলে টাইপ চেক সহ আপনাকে যুক্ত করতে হবে। এবং যদি আপনি না করেন তবে আপনি কখনই সংকলনের সময় জানতে পারবেন না।

ভিজিটর প্যাটার্নের সাহায্যে আপনি আপনার কোডটি পরিষ্কার করতে পারেন যেহেতু এটি খোলা / বন্ধ নীতি লঙ্ঘন করে না এবং একক দায়িত্ব লঙ্ঘন করে না। এবং আপনি যদি ভিজিট বাস্তবায়ন করতে ভুলে যান তবে এটি সংকলন করবে না:

public abstract class Employee
{
    public abstract void Accept(EmployeeVisitor v);
}

public class SalariedEmployee : Employee
{
    public override void Accept(EmployeeVisitor v)
    {
        v.Visit(this);
    }
}

public class HourlyEmployee:Employee
{
    public override void Accept(EmployeeVisitor v)
    {
        v.Visit(this);
    }
}

public interface EmployeeVisitor
{
    void Visit(HourlyEmployee he);
    void Visit(SalariedEmployee se);
}

public class QtdHoursAndPayReport : EmployeeVisitor
{
    public void Visit(HourlyEmployee he)
    {
        System.Diagnostics.Debug.WriteLine("hourly");
        // generate the line of the report.
    }
    public void Visit(SalariedEmployee se)
    {
        System.Diagnostics.Debug.WriteLine("fix");
    } // do nothing

    public void PrintReport()
    {
        var employees = new List<Employee>
        {
            new SalariedEmployee(),
            new HourlyEmployee()
        };
        QtdHoursAndPayReport v = new QtdHoursAndPayReport();
        foreach (var emp in employees)
        {
            emp.Accept(v);
        }
    }
}

class Program
{

    public static void Main(string[] args)
    {
        new QtdHoursAndPayReport().PrintReport();
    }       
}  
}

যাদুটি তখন v.Visit(this) একইরকম দেখতে এটি বাস্তবে ভিন্ন কারণ এটি দর্শকদের বিভিন্ন ওভারলোড ।


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

3

@ ফেডেরিকো এ রামপনি এর দুর্দান্ত উত্তরের ভিত্তিতে।

আপনার এই শ্রেণিবদ্ধতাটি কেবল কল্পনা করুন:

public interface IAnimal
{
    void DoSound();
}

public class Dog : IAnimal
{
    public void DoSound()
    {
        Console.WriteLine("Woof");
    }
}

public class Cat : IAnimal
{
    public void DoSound(IOperation o)
    {
        Console.WriteLine("Meaw");
    }
}

এখানে যদি আপনার "ওয়াক" পদ্ধতি যুক্ত করার দরকার হয় তবে কী হবে? এটি পুরো ডিজাইনের জন্য বেদনাদায়ক হবে।

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

সুতরাং, কেবল এই সি # উদাহরণটি পরীক্ষা করে চালান:

using System;
using System.Collections.Generic;

namespace VisitorPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            var animals = new List<IAnimal>
            {
                new Cat(), new Cat(), new Dog(), new Cat(), 
                new Dog(), new Dog(), new Cat(), new Dog()
            };

            foreach (var animal in animals)
            {
                animal.DoOperation(new Walk());
                animal.DoOperation(new Sound());
            }

            Console.ReadLine();
        }
    }

    public interface IOperation
    {
        void PerformOperation(Dog dog);
        void PerformOperation(Cat cat);
    }

    public class Walk : IOperation
    {
        public void PerformOperation(Dog dog)
        {
            Console.WriteLine("Dog walking");
        }

        public void PerformOperation(Cat cat)
        {
            Console.WriteLine("Cat Walking");
        }
    }

    public class Sound : IOperation
    {
        public void PerformOperation(Dog dog)
        {
            Console.WriteLine("Woof");
        }

        public void PerformOperation(Cat cat)
        {
            Console.WriteLine("Meaw");
        }
    }

    public interface IAnimal
    {
        void DoOperation(IOperation o);
    }

    public class Dog : IAnimal
    {
        public void DoOperation(IOperation o)
        {
            o.PerformOperation(this);
        }
    }

    public class Cat : IAnimal
    {
        public void DoOperation(IOperation o)
        {
            o.PerformOperation(this);
        }
    }
}

পদব্রজে ভ্রমণ, খাওয়া উপযুক্ত উদাহরণ যেহেতু উভয় করতে চলেছেন সাধারণ তারা না Dogসেইসাথে Cat। আপনি এগুলি বেস শ্রেণিতে তৈরি করতে পারতেন যাতে তারা উত্তরাধিকার সূত্রে প্রাপ্ত হয় বা একটি উপযুক্ত উদাহরণ বেছে নেয় pick
অভিনব গৌনিয়াল

শব্দগুলি পৃথক, ভাল নমুনা, তবে এটির সাথে দর্শকের প্যাটার্নের কোনও সম্পর্ক আছে কিনা তা সম্পর্কে নিশ্চিত হওয়া যায় না
ডাগ

3

দর্শনার্থী

দর্শনার্থী ক্লাসের পরিবারে নিজেরাই ক্লাস পরিবর্তন না করে নতুন ভার্চুয়াল ফাংশন যুক্ত করার অনুমতি দেয়; পরিবর্তে, কেউ একটি দর্শনার্থী শ্রেণি তৈরি করে যা ভার্চুয়াল ফাংশনটির উপযুক্ত সমস্ত বিশেষায়িতকরণ প্রয়োগ করে

দর্শনার্থী কাঠামো:

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

ভিজিটর প্যাটার্ন ব্যবহার করুন যদি:

  1. অনুরূপ অপারেশন করতে হবেকাঠামোর মধ্যে গোষ্ঠীযুক্ত বিভিন্ন ধরণের অবজেক্টগুলিতে
  2. আপনাকে অনেকগুলি স্বতন্ত্র এবং সম্পর্কিত সম্পর্কিত অপারেশন সম্পাদন করতে হবে need এটি অপারেশনকে অবজেক্টস স্ট্রাকচার থেকে আলাদা করে দেয়
  3. অবজেক্ট স্ট্রাকচার পরিবর্তন না করেই নতুন অপারেশন যুক্ত করতে হবে
  4. আপনাকে ক্লাস পরিবর্তন করতে বা প্রাপ্ত করার পরিবর্তে একক শ্রেণিতে সম্পর্কিত ক্রিয়াকলাপ সংগ্রহ করুন ather
  5. শ্রেণীর পাঠাগারগুলিতে ফাংশন যুক্ত করুন যার জন্য আপনার কাছে উত্স নেই বা উত্সটি পরিবর্তন করতে পারবেন না

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

যদি কোনও নতুন ভিজিবল অবজেক্ট যুক্ত করা হয় তবে এর জন্য ভিজিটর এবং কংক্রিটভিসিটার শ্রেণিতে কোড পরিবর্তন দরকার । এই ইস্যুটি মোকাবিলার জন্য একটি কর্মপরিকল্পনা রয়েছে: প্রতিবিম্বটি ব্যবহার করুন, যা কার্য সম্পাদনে প্রভাব ফেলবে।

টুকিটাকি সংকেতলিপি:

import java.util.HashMap;

interface Visitable{
    void accept(Visitor visitor);
}

interface Visitor{
    void logGameStatistics(Chess chess);
    void logGameStatistics(Checkers checkers);
    void logGameStatistics(Ludo ludo);    
}
class GameVisitor implements Visitor{
    public void logGameStatistics(Chess chess){
        System.out.println("Logging Chess statistics: Game Completion duration, number of moves etc..");    
    }
    public void logGameStatistics(Checkers checkers){
        System.out.println("Logging Checkers statistics: Game Completion duration, remaining coins of loser");    
    }
    public void logGameStatistics(Ludo ludo){
        System.out.println("Logging Ludo statistics: Game Completion duration, remaining coins of loser");    
    }
}

abstract class Game{
    // Add game related attributes and methods here
    public Game(){

    }
    public void getNextMove(){};
    public void makeNextMove(){}
    public abstract String getName();
}
class Chess extends Game implements Visitable{
    public String getName(){
        return Chess.class.getName();
    }
    public void accept(Visitor visitor){
        visitor.logGameStatistics(this);
    }
}
class Checkers extends Game implements Visitable{
    public String getName(){
        return Checkers.class.getName();
    }
    public void accept(Visitor visitor){
        visitor.logGameStatistics(this);
    }
}
class Ludo extends Game implements Visitable{
    public String getName(){
        return Ludo.class.getName();
    }
    public void accept(Visitor visitor){
        visitor.logGameStatistics(this);
    }
}

public class VisitorPattern{
    public static void main(String args[]){
        Visitor visitor = new GameVisitor();
        Visitable games[] = { new Chess(),new Checkers(), new Ludo()};
        for (Visitable v : games){
            v.accept(visitor);
        }
    }
}

ব্যাখ্যা:

  1. Visitable( Element) একটি ইন্টারফেস এবং এই ইন্টারফেস পদ্ধতিটি ক্লাসের সেটগুলিতে যুক্ত করতে হবে।
  2. Visitorএকটি ইন্টারফেস, যা Visitableউপাদানগুলিতে একটি অপারেশন করার পদ্ধতি রয়েছে ।
  3. GameVisitorএকটি শ্রেণি, যা Visitorইন্টারফেস প্রয়োগ করে ( ConcreteVisitor)।
  4. প্রতিটি Visitableউপাদান ইন্টারফেসের Visitorএকটি প্রাসঙ্গিক পদ্ধতি গ্রহণ করে এবং প্রার্থনা করে Visitor
  5. আপনি বিবেচনা করতে পারেন Gameহিসাবে Elementএবং জমাটবদ্ধ গেম চান Chess,Checkers and Ludoহিসাবে ConcreteElements

উপরের উদাহরণে, Chess, Checkers and Ludoতিনটি আলাদা গেম (এবং Visitableক্লাস) রয়েছে। এক দুর্দান্ত দিনে, আমি প্রতিটি গেমের পরিসংখ্যান লগ করতে একটি দৃশ্যের মুখোমুখি হয়েছি। সুতরাং পরিসংখ্যান কার্যকারিতা বাস্তবায়নের জন্য স্বতন্ত্র শ্রেণিকে পরিবর্তন না করে আপনি সেই দায়িত্বটিকে কেন্দ্রিয় করতে পারেনGameVisitor শ্রেণিতে , যা প্রতিটি গেমের কাঠামো পরিবর্তন না করে আপনার জন্য কৌশল করে।

আউটপুট:

Logging Chess statistics: Game Completion duration, number of moves etc..
Logging Checkers statistics: Game Completion duration, remaining coins of loser
Logging Ludo statistics: Game Completion duration, remaining coins of loser

নির্দেশ করে

ওডসাইন নিবন্ধ

উত্স তৈরির নিবন্ধ

বিস্তারিত জানার জন্য

প্রসাধক

প্যাটার্নটি একই শ্রেণীর অন্যান্য বস্তুর আচরণকে প্রভাবিত না করে স্থিতিশীলভাবে বা গতিশীলভাবে কোনও পৃথক বস্তুতে আচরণ যুক্ত করতে দেয়

সম্পর্কিত পোস্ট:

আইও এর জন্য সজ্জিত প্যাটার্ন

সজ্জিত প্যাটার্ন কখন ব্যবহার করবেন?


2

আমি http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Visitor.html থেকে বর্ণনা এবং উদাহরণটি সত্যিই পছন্দ করি ।

অনুমানটি হ'ল আপনার কাছে একটি প্রাথমিক শ্রেণীর শ্রেণিবদ্ধতা স্থির হয়েছে; সম্ভবত এটি অন্য বিক্রেতার কাছ থেকে এবং আপনি সেই শ্রেণিবিন্যাসে পরিবর্তন করতে পারবেন না। তবে আপনার অভিপ্রায়টি হ'ল আপনি সেই শ্রেণিবিন্যাসে নতুন পলিমারফিক পদ্ধতি যুক্ত করতে চান, যার অর্থ সাধারণত আপনি বেস বর্গ ইন্টারফেসে কিছু যুক্ত করতে চান। সুতরাং দ্বিধা হ'ল আপনার বেস ক্লাসে পদ্ধতি যুক্ত করা দরকার তবে আপনি বেস ক্লাসটি স্পর্শ করতে পারবেন না। আপনি কিভাবে এই কাছাকাছি পেতে?

ডিজাইনের ধরণ যা এই ধরণের সমস্যা সমাধান করে তাকে "দর্শনার্থী" (ডিজাইন প্যাটার্নস বইয়ের চূড়ান্ত চিত্র) বলা হয় এবং এটি শেষ বিভাগে প্রদর্শিত ডাবল প্রেরণ প্রকল্পের উপর ভিত্তি করে।

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


প্রযুক্তিগতভাবে ভিজিটর প্যাটার্নটি তাদের উদাহরণ থেকে এটি কেবলমাত্র প্রাথমিক দ্বৈত প্রেরণ। আমি যুক্তি দেব যে দরকারীতা এটি একা থেকে বিশেষভাবে দেখা যায় না।
জর্জ মাউয়ার

1

আমি কখন এবং কখন বুঝতে পেরেছি, কখনই আমি বুঝতে পারি নি। যদি এটি সি ++ এর মতো কোনও পটভূমিতে যে কাউকে সহায়তা করে, আপনি এটিকে খুব মনোযোগ দিয়ে পড়তে চান want

অলসতার জন্য আমরা ভিজিটর প্যাটার্নটি ব্যবহার করি কারণ "যখন ভার্চুয়াল ফাংশনগুলি গতিশীলভাবে সি ++ তে প্রেরণ করা হয়, তখন ফাংশন ওভারলোডিং স্থিরভাবে করা হয়"

অথবা, অন্য কোনও উপায় রাখুন, আপনি যখন কোনও স্পেসশিপ রেফারেন্সটি পাস করেন যা আসলে কোনও অ্যাপোলোস্পেসক্রাফ্ট অবজেক্টের সাথে আবদ্ধ হয় তখন কলিডউইথ (অ্যাপোলোস্পেসক্র্যাফ্ট &) বলা হয় তা নিশ্চিত করার জন্য way

class SpaceShip {};
class ApolloSpacecraft : public SpaceShip {};
class ExplodingAsteroid : public Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    cout << "ExplodingAsteroid hit a SpaceShip" << endl;
  }
  virtual void CollideWith(ApolloSpacecraft&) {
    cout << "ExplodingAsteroid hit an ApolloSpacecraft" << endl;
  }
}

2
ভিজিটর প্যাটার্নে ডায়নামিক প্রেরণের ব্যবহার আমাকে পুরোপুরি বিভ্রান্ত করে। প্যাটার্নের প্রস্তাবিত ব্যবহারগুলি ব্রাঞ্চকে বর্ণনা করে যা সংকলন সময়ে করা যায়। এই কেসগুলি একটি ফাংশন টেম্পলেট দিয়ে আপাতদৃষ্টিতে ভাল হবে।
প্রেক্সোলাইটিক

0

@ ফেডেরিকো এ রামপোনির দুর্দান্ত ব্যাখ্যার জন্য ধন্যবাদ , আমি কেবল এটি জাভাতে তৈরি করেছি সংস্করণে । আশা করি এটি সহায়ক হতে পারে।

@ কনরাড রুডল্ফ যেমন উল্লেখ করেছেন, এটি আসলে দুটি ব্যবহার করে একটি ডাবল প্রেরণ রান-টাইম পদ্ধতিগুলি নির্ধারণের জন্য এটি কংক্রিটের উদাহরণ ।

সুতরাং প্রকৃতপক্ষে অপারেশন এক্সিকিউটারের জন্য একটি সাধারণ ইন্টারফেস তৈরি করার দরকার নেই যতক্ষণ না আমাদের অপারেশন ইন্টারফেসটি সঠিকভাবে সংজ্ঞায়িত করা হয়।

import static java.lang.System.out;
public class Visitor_2 {
    public static void main(String...args) {
        Hearen hearen = new Hearen();
        FoodImpl food = new FoodImpl();
        hearen.showTheHobby(food);
        Katherine katherine = new Katherine();
        katherine.presentHobby(food);
    }
}

interface Hobby {
    void insert(Hearen hearen);
    void embed(Katherine katherine);
}


class Hearen {
    String name = "Hearen";
    void showTheHobby(Hobby hobby) {
        hobby.insert(this);
    }
}

class Katherine {
    String name = "Katherine";
    void presentHobby(Hobby hobby) {
        hobby.embed(this);
    }
}

class FoodImpl implements Hobby {
    public void insert(Hearen hearen) {
        out.println(hearen.name + " start to eat bread");
    }
    public void embed(Katherine katherine) {
        out.println(katherine.name + " start to eat mango");
    }
}

যেমনটি আপনি প্রত্যাশা করছেন, একটি সাধারণ ইন্টারফেস আমাদের আরও স্বচ্ছতা এনে দেবে যদিও এটি প্রকৃতপক্ষে এই প্যাটার্নটির প্রয়োজনীয় অংশ নয় ।

import static java.lang.System.out;
public class Visitor_2 {
    public static void main(String...args) {
        Hearen hearen = new Hearen();
        FoodImpl food = new FoodImpl();
        hearen.showHobby(food);
        Katherine katherine = new Katherine();
        katherine.showHobby(food);
    }
}

interface Hobby {
    void insert(Hearen hearen);
    void insert(Katherine katherine);
}

abstract class Person {
    String name;
    protected Person(String n) {
        this.name = n;
    }
    abstract void showHobby(Hobby hobby);
}

class Hearen extends  Person {
    public Hearen() {
        super("Hearen");
    }
    @Override
    void showHobby(Hobby hobby) {
        hobby.insert(this);
    }
}

class Katherine extends Person {
    public Katherine() {
        super("Katherine");
    }

    @Override
    void showHobby(Hobby hobby) {
        hobby.insert(this);
    }
}

class FoodImpl implements Hobby {
    public void insert(Hearen hearen) {
        out.println(hearen.name + " start to eat bread");
    }
    public void insert(Katherine katherine) {
        out.println(katherine.name + " start to eat mango");
    }
}

0

আপনার প্রশ্নটি কখন জানতে হবে:

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

//psuedo code
    if(payPal) 
    do paypal checkout 
    if(stripe)
    do strip stuff checkout
    if(payoneer)
    do payoneer checkout

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

new PaymentCheckoutVistor(paymentType).visit()

আপনি এখানে উদাহরণের সংখ্যা থেকে এটি কীভাবে বাস্তবায়ন করবেন তা দেখতে পাচ্ছেন, কেবলমাত্র আপনাকে একটি ইউকেকেস দেখাচ্ছে।

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