ভিজিটর প্যাটার্নে গ্রহণযোগ্য () পদ্ধতিটি কী?


88

ক্লাস থেকে অ্যালগরিদমগুলি ডিকম্পল করার বিষয়ে অনেক কথা হয়। তবে, একটি বিষয় আলাদা করে বলা যায় না।

তারা এইভাবে ভিজিটর ব্যবহার করে

abstract class Expr {
  public <T> T accept(Visitor<T> visitor) {visitor.visit(this);}
}

class ExprVisitor extends Visitor{
  public Integer visit(Num num) {
    return num.value;
  }

  public Integer visit(Sum sum) {
    return sum.getLeft().accept(this) + sum.getRight().accept(this);
  }

  public Integer visit(Prod prod) {
    return prod.getLeft().accept(this) * prod.getRight().accept(this);
  }

ভিজিটকে সরাসরি (এলিমেন্ট) কল করার পরিবর্তে ভিজিটর উপাদানটিকে তার ভিজিট পদ্ধতিতে কল করতে বলে। এটি দর্শনার্থীদের সম্পর্কে ক্লাস অজ্ঞাততার ঘোষিত ধারণার বিরোধিতা করে।

পিএস 1 দয়া করে আপনার নিজের শব্দ দিয়ে ব্যাখ্যা করুন বা সঠিক ব্যাখ্যায় নির্দেশ করুন। কারণ দুটি প্রতিক্রিয়া আমি সাধারণ এবং অনিশ্চিত কিছু উল্লেখ করেছি।

পিএস 2 আমার অনুমান: যেহেতু getLeft()বেসিকটি রিটার্ন দেয় Expression, কলিংয়ের visit(getLeft())ফলাফল আসে visit(Expression), যেখানে getLeft()কলিংয়ের visit(this)ফলশ্রুতি অন্য, আরও উপযুক্ত, ভিজিটের অনুরোধে আসবে। সুতরাং, accept()ধরণের রূপান্তর (ওরফে কাস্টিং) সম্পাদন করে।

PS3 স্কালার প্যাটার্ন ম্যাচিং = স্টেরয়েডের ভিজিটর প্যাটার্নটি গ্রহণযোগ্য পদ্ধতি ছাড়াই ভিজিটর প্যাটার্নটি কতটা সহজ তা দেখায়। উইকিপিডিয়া এই বিবৃতিতে যুক্ত করেছে : একটি কাগজ যুক্ত করে যে " accept()প্রতিবিম্ব পাওয়া যায় তখন পদ্ধতিগুলি অপ্রয়োজনীয়; কৌশলটির জন্য 'ওয়াকআউটআউট' শব্দটি প্রবর্তন করে।"



এটিতে বলা হয়েছে, "যখন ভিজিটর কল গ্রহণ করে, কলটি কলির প্রকারের ভিত্তিতে প্রেরণ করা হয় Then অন্য কথায়, এটি এমন জিনিসটি বলে যা আমাকে বিভ্রান্ত করে। এই কারণে, আপনি কি আরও নির্দিষ্ট হতে পারেন?
Val,

উত্তর:


155

সি-জাতীয় ভাষাগুলির (সি #, জাভা, ইত্যাদি) শব্দার্থক কারণে ভিজিটর প্যাটার্নের visit/ নির্মাণগুলি acceptএকটি প্রয়োজনীয় মন্দ। দর্শনার্থী প্যাটার্নের লক্ষ্য হ'ল আপনার কোডটি পড়ার প্রত্যাশা মতো আপনার কলটি রুট করতে ডাবল-প্রেরণ ব্যবহার করা।

সাধারণত যখন ভিজিটর প্যাটার্নটি ব্যবহৃত হয়, তখন কোনও বস্তু শ্রেণিবিন্যাস জড়িত থাকে যেখানে সমস্ত নোড বেস Nodeধরণের থেকে প্রাপ্ত হয় , এখন থেকে হিসাবে উল্লেখ করা হয় Node। সহজাতভাবে, আমরা এটি এটি লিখতে চাই:

Node root = GetTreeRoot();
new MyVisitor().visit(root);

এর মধ্যেই সমস্যা রয়েছে। যদি আমাদের MyVisitorক্লাসটি নিম্নলিখিতগুলির মতো সংজ্ঞায়িত হয়:

class MyVisitor implements IVisitor {
  void visit(CarNode node);
  void visit(TrainNode node);
  void visit(PlaneNode node);
  void visit(Node node);
}

যদি, রানটাইমে, প্রকৃত প্রকারটি নির্বিশেষে root, আমাদের কলটি ওভারলোডের মধ্যে চলে যায় visit(Node node)। প্রকারের ঘোষিত সমস্ত ভেরিয়েবলের ক্ষেত্রে এটি সত্য হবে Node। কেন? যেহেতু জাভা এবং অন্যান্য সি-এর মতো ভাষাগুলি কোন স্থির প্রকারটিকে বিবেচনা করে বা কোন ওভারলোডটি কল করতে হবে তা স্থির করার সময় প্যারামিটারের স্থিতিশীল প্রকার বা প্রকারটিকে যে ধরণের হিসাবে ঘোষণা করা হয় তা বিবেচনা করে। জাভা প্রতিটি পদ্ধতির কলের জন্য রানটাইমের সময় জিজ্ঞাসা করার জন্য অতিরিক্ত পদক্ষেপ নেয় না, "ঠিক আছে, ডায়নামিক ধরণের rootকী? ওহ, আমি দেখি। এটি একটি TrainNode। দেখা যাক যে কোনও পদ্ধতিতে MyVisitorটাইপের একটি পরামিতি গ্রহণ করা আছে কিনা?TrainNode... "। সংকলনের সময় সংকলক নির্ধারণ করে যে কোন পদ্ধতিটি ডাকা হবে be (জাভা যদি আর্গুমেন্টগুলির গতিশীল প্রকারগুলি পরীক্ষা করে দেখায় তবে পারফরম্যান্সটি ভয়াবহ হতে পারে))

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

দর্শনার্থীর প্যাটার্নটির লক্ষ্য হ'ল ডাবল-প্রেরণ সম্পাদন করা - কল টার্গেটের ধরণটি কেবল বিবেচনা করা হয় না ( MyVisitor, ভার্চুয়াল পদ্ধতিগুলির মাধ্যমে), তবে প্যারামিটারের ধরণ ( Nodeআমরা কী ধরণের দিকে তাকিয়ে আছি)? ভিজিটার প্যাটার্নটি আমাদের visit/ acceptসংমিশ্রণ দ্বারা এটি করতে দেয় ।

আমাদের লাইন এটিতে পরিবর্তন করে:

root.accept(new MyVisitor());

আমরা যা চাই তা আমরা পেতে পারি: ভার্চুয়াল পদ্ধতি প্রেরণের মাধ্যমে আমরা সাবক্লাস দ্বারা প্রয়োগকৃত সঠিক স্বীকৃতি () কলটি প্রবেশ করান - আমাদের উদাহরণে TrainElement, TrainElementএর প্রয়োগ বাস্তবায়িত করব accept():

class TrainNode extends Node implements IVisitable {
  void accept(IVisitor v) {
    v.visit(this);
  }
}

কি পরিধি ভিতরে এই সময়ে কম্পাইলার কি জানে, TrainNodeএর accept? এটি জানে যে স্ট্যাটিক ধরণের thisএকটিTrainNode । এটি তথ্যের একটি গুরুত্বপূর্ণ অতিরিক্ত বিচ্ছিন্নতা যা সংকলকটি আমাদের কলারের সুযোগ সম্পর্কে সচেতন ছিল না: সেখানে, এটি সম্পর্কে rootযা জানত তা ছিল এটি একটি Node। এখন সংকলক জানে যে this( root) কেবল একটি নয় Node, তবে এটি আসলে একটি TrainNode। ফল ইন, এক লাইন ভিতরে পাওয়া accept(): v.visit(this), সম্পূর্ণরূপে অন্য কিছু মানে। কম্পাইলার এখন একটি জমিদার জন্য চেহারা ইচ্ছার visit()করে একটি সময় লাগে TrainNode। যদি এটির সন্ধান না করে তবে এটি কলটি একটি ওভারলোডের ক্ষেত্রে সংকলন করবে যা একটি গ্রহণ করেNode। যদি উভয়ই বিদ্যমান না থাকে তবে আপনি একটি সংকলন ত্রুটি পাবেন (যদি না আপনার কোনও ওভারলোড লাগে তবে object)। কার্যকরভাবে এইভাবে আমরা সমস্ত বরাবর যা ইচ্ছা করে তা প্রবেশ করবে: MyVisitorএর বাস্তবায়ন visit(TrainNode e)। কোনও ক্যাসেটের প্রয়োজন ছিল না, এবং সবচেয়ে গুরুত্বপূর্ণ, কোনও প্রতিবিম্বের প্রয়োজন ছিল না। সুতরাং, এই প্রক্রিয়াটির ওভারহেড বরং কম: এটি কেবলমাত্র পয়েন্টার রেফারেন্স এবং অন্য কিছু দিয়ে থাকে।

আপনি আপনার প্রশ্নে ঠিক আছেন - আমরা একটি castালাই ব্যবহার করতে পারি এবং সঠিক আচরণ পেতে পারি। যাইহোক, প্রায়শই, আমরা এমনকি নোড কি টাইপ জানি না। নিম্নলিখিত শ্রেণিবদ্ধের ক্ষেত্রে নিন:

abstract class Node { ... }
abstract class BinaryNode extends Node { Node left, right; }
abstract class AdditionNode extends BinaryNode { }
abstract class MultiplicationNode extends BinaryNode { }
abstract class LiteralNode { int value; }

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

class Interpreter implements IVisitor<int> {
  int visit(AdditionNode n) {
    int left = n.left.accept(this);
    int right = n.right.accept(this); 
    return left + right;
  }
  int visit(MultiplicationNode n) {
    int left = n.left.accept(this);
    int right = n.right.accept(this);
    return left * right;
  }
  int visit(LiteralNode n) {
    return n.value;
  }
}

কাস্টিং আমাদের সুদূর পেতে হবে না, যেহেতু আমরা ধরনের জানি না leftবা rightvisit()পদ্ধতি। আমাদের পার্সার সম্ভবত সম্ভবত Nodeশ্রেণিবিন্যাসের মূলের দিকে ইঙ্গিত করা টাইপের একটি বস্তুও ফিরিয়ে আনবে , তাই আমরা নিরাপদে এটি কাস্ট করতে পারি না। সুতরাং আমাদের সাধারণ দোভাষীটি দেখতে পাবেন:

Node program = parse(args[0]);
int result = program.accept(new Interpreter());
System.out.println("Output: " + result);

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

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


4
কার্যকর জাভা আইটেম # 41 এ এই সতর্কতাটি অন্তর্ভুক্ত করেছে: " একই পরামিতিগুলির সেটগুলি কাস্টগুলি যোগ করে বিভিন্ন ওভারলোডিংগুলিতে যেতে পারে এমন পরিস্থিতিগুলি এড়িয়ে চলুন avoid " accept()এই সতর্কতাটি যখন ভিজিটর লঙ্ঘন করা হয় তখন পদ্ধতিটি প্রয়োজনীয় হয়ে ওঠে।
jaco0646

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

আমার কাছে মনে হয় যে জাভাতে আমাদের গ্রহণযোগ্য পদ্ধতির দরকার নেই কারণ জাভাতে আমরা সর্বদা সুনির্দিষ্ট ধরণের পদ্ধতিটি কল করি
গিলাদ বারুচিয়ান

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

@ গিলাদ বারুচিয়ান, সংকলক সুনির্দিষ্ট নির্দিষ্ট পদ্ধতিতে একটি কল উত্পন্ন করে যা সংকলক নির্ধারণ করতে পারে।
মিম্বুডাব্লু

15

অবশ্যই যে নির্বোধ হবে যদি একমাত্র উপায় হিসাবে গ্রহণের বাস্তবায়ন হয়।

তবে তা নয়।

উদাহরণস্বরূপ, শ্রেণিবিন্যাসের সাথে ডিল করার সময় দর্শনার্থীরা সত্যই কার্যকর হয় সেই ক্ষেত্রে নন-টার্মিনাল নোডের বাস্তবায়ন এই জাতীয় কিছু হতে পারে

interface IAcceptVisitor<T> {
  void Accept(IVisit<T> visitor);
}
class HierarchyNode : IAcceptVisitor<HierarchyNode> {
  public void Accept(IVisit<T> visitor) {
    visitor.visit(this);
    foreach(var n in this.children)
      n.Accept(visitor);
  }

  private IEnumerable<HierarchyNode> children;
  ....
}

দেখেন তো? আপনি মূ .় হিসাবে যা বর্ণনা করেন তা হায়ারার্কিগুলি অনুসরণ করার সমাধান।

এখানে অনেক দীর্ঘ এবং গভীর নিবন্ধ যা আমাকে দর্শকদের বুঝতে সাহায্য করেছে

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


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

4
রুটিন ট্র্যাভারসালের পক্ষে গ্রহণযোগ্যতা হ'ল বলাই যুক্তিযুক্ত এবং সাধারণ জনগণের পক্ষে মূল্যবান। তবে, আমি অন্য কারও কাছ থেকে আমার উদাহরণটি নিয়েছি "আমি andymaleh.blogspot.com/2008/04/… না পড়া পর্যন্ত আমি ভিজিটর ধরণটি বুঝতে পারি না "। এই উদাহরণ বা উইকিপিডিয়া বা অন্যান্য উত্তরগুলি নেভিগেশন সুবিধার কথা উল্লেখ করে না। তবুও, তারা সকলেই এই নির্বোধকে () মেনে নেওয়ার দাবি করে। এজন্যই আমার প্রশ্ন জিজ্ঞাসা করুন: কেন?
Val,

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

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

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

0

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

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

এই সমস্যাটি এড়াতে দর্শনার্থীর ধরণটি (কমপক্ষে) তিনটি পদ্ধতির প্রস্তাব দেয়:

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

দর্শনার্থীর প্যাটার্ন ব্যতীত, যদি কলিং সফ্টওয়্যার কোনও কঠোর লকিং / আনলকিং প্রোটোকল অনুসরণ করতে ব্যর্থ হয় তবে পারমাণবিক আপডেটগুলি সম্পাদন করতে লকগুলি ফাঁস করা এবং ঝুঁকির ঝুঁকির প্রয়োজন হয়। ভিজিটর প্যাটার্নের সাথে, পারমাণবিক আপডেটগুলি তুলনামূলকভাবে নিরাপদে করা যায়।


4
1. ভিজিট করার অর্থ হ'ল আপনার কেবল পরিদর্শন করা সর্বজনীন পদ্ধতিতে অ্যাক্সেস রয়েছে যাতে ভিজিটরের সাথে জনসাধারণের জন্য উপযোগী হওয়ার জন্য অভ্যন্তরীণ লকগুলি অ্যাক্সেসযোগ্য করে তোলা দরকার। 2 / আমি এর আগে যে উদাহরণগুলি দেখেছি তার কোনওটিই বোঝাচ্ছে না যে দর্শনার্থীর দেখার স্থিতি পরিবর্তনের জন্য ব্যবহৃত হবে। ৩. "traditionalতিহ্যবাহী ভিজিটর প্যাটার্নের সাহায্যে, আমরা কোনও নোডে প্রবেশ করব তখনই কেবল তা নির্ধারণ করা যায় current আমরা বর্তমান নোডটি প্রবেশ করার আগে আমরা আগের নোডটি রেখে গেছি কিনা তা আমরা জানি না don't" আপনি কেবলমাত্র ভিজিটএন্টার এবং ভিজিটলাইভের পরিবর্তে কেবল দেখার সাথে কীভাবে আনলক করবেন? পরিশেষে, আমি ভিজিটরের চেয়ে অ্যাকপেট () এর অ্যাপ্লিকেশন সম্পর্কে জিজ্ঞাসা করেছি।
Val,

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

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

0

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

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


-1

উত্স কোড সংকলন একটি ভাল উদাহরণ:

interface CompilingVisitor {
   build(SourceFile source);
}

ক্লায়েন্টদের মধ্যে একটি বাস্তবায়ন করতে পারে JavaBuilder, RubyBuilder, XMLValidator, ইত্যাদি এবং প্রকল্পে সংগ্রহ এবং সমস্ত সোর্স ফাইল পরিদর্শন করার জন্য বাস্তবায়ন পরিবর্তনের দরকার নেই।

যদি আপনার প্রতিটি উত্সের ফাইলের জন্য পৃথক ক্লাস থাকে তবে এটি একটি খারাপ প্যাটার্ন হবে:

interface CompilingVisitor {
   build(JavaSourceFile source);
   build(RubySourceFile source);
   build(XMLSourceFile source);
}

এটি প্রসঙ্গে নেমে আসে এবং সিস্টেমের কোন অংশগুলি আপনি বর্ধনযোগ্য হতে চান।


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