ডাবল প্রেরণ ঠিক এই প্যাটার্নটি ব্যবহারের জন্য অন্যদের মধ্যে একটি কারণ ।
তবে মনে রাখবেন যে ভাষাগুলিতে একক প্রেরণের দৃষ্টান্ত ব্যবহার করে দ্বিগুণ বা অধিক প্রেরণের প্রয়োগের একক উপায় এটি।
প্যাটার্নটি ব্যবহার করার কারণ এখানে রয়েছে:
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)