প্যারামিটারগুলি পাস করার জন্য (বিরোধী) প্যাটার্নির কোনও নাম রয়েছে যা কেবলমাত্র কল চেইনের বেশ কয়েকটি স্তরের গভীরে ব্যবহৃত হবে?


208

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

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

higherlevel(newParam)->level1(newParam)->level2(newParam)->level3(newParam)

newParamআমার উদাহরণে যেখানে আগে বিশ্বব্যাপী পরিবর্তনশীল ছিল, তবে এটি পরিবর্তে আগের হার্ডকোডযুক্ত মান হতে পারে। মুল বক্তব্যটি হ'ল এখন নিউপ্যারামের মান পাওয়া গেছে higherlevel()এবং সমস্ত পথে "ভ্রমণ" করতে হবে level3()

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

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


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

8
একটি নির্দিষ্ট উত্তর পেতে এটি একধরণের বিস্তৃত বর্ণালী। এই স্তরে, আমি এটিকে "কোডিং" বলি।
মাচাদো

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

7
যদিও এটি একটি ভাল প্যাটার্ন / অ্যান্টিপ্যাটার্ন / ধারণা / সমাধান কিনা তা নিয়ে আমি আলোচনার প্রশংসা করি, আমি আসলে যা জানতে চেয়েছিলাম তার নাম আছে কিনা তা।
ecerulm

3
আমিও শুনেছি এটা বলা থ্রেডিং হিসেবে সবচেয়ে বেশি যে, কিন্তু নদীর গভীরতানির্ণয় , একটি কমিয়ে হিসেবে পুরাদস্তর লাইন কল স্ট্যাক সর্বত্র।
wchargin

উত্তর:


202

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

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

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


73
"ট্র্যাম্প ডেটা" অনুসন্ধান করে আমি আমার সাফারি সাবস্ক্রিপশনে "কোড সম্পূর্ণ" বইটি সন্ধান করতে সক্ষম হয়েছি। বইয়ের একটি অংশ রয়েছে "বৈশ্বিক ডেটা ব্যবহারের কারণ" নামে একটি কারণ রয়েছে এবং এর অন্যতম কারণ হ'ল "গ্লোবাল ডেটা ব্যবহার ট্রাম্পের ডেটা দূর করতে পারে"। :)। আমার মনে হচ্ছে "ট্র্যাম্প ডেটা" আমাকে গ্লোবালগুলি নিয়ে কাজ করার বিষয়ে আরও সাহিত্য সন্ধান করার অনুমতি দেবে। ধন্যবাদ!
ecerulm

9
@ জিমি জেমস, এই ফাংশনগুলি অবশ্যই কার্যকরভাবে কাজ করে। ঠিক সেই নির্দিষ্ট নতুন পরামিতিটি দিয়ে নয় যা আগে কেবল একটি বিশ্বব্যাপী ছিল।
ecerulm

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

6
কিছু বৈশ্বিক তথ্য ঠিক আছে। এটিকে "গ্লোবাল ডেটা" বলার পরিবর্তে আপনি এটিকে "পরিবেশ" বলতে পারেন - কারণ এটি এটি। পরিবেশের মধ্যে অন্তর্ভুক্ত থাকতে পারে, উদাহরণস্বরূপ, অ্যাপডাটা (উইন্ডোজে) এর জন্য একটি স্ট্রিং পাথ বা আমার বর্তমান প্রকল্পে জিডিআই + ব্রাশ, কলম, ফন্ট এবং এর সমস্ত সেট সমস্ত উপাদান দ্বারা ব্যবহৃত।
রবিনসন

7
@ রবিনসন উদাহরণস্বরূপ, আপনি কি সত্যিই চান আপনার চিত্র লেখার কোডটি% AppData% স্পর্শ করতে চান, না আপনি বরং এটি কোথায় লিখতে হবে তার পক্ষে যুক্তি নেবেন? এটি বৈশ্বিক রাষ্ট্র এবং একটি যুক্তির মধ্যে পার্থক্য। "পরিবেশ" কেবল সহজেই একটি ইঞ্জেকড নির্ভরতা হতে পারে, কেবল যারা পরিবেশের সাথে যোগাযোগের জন্য দায়বদ্ধ তাদের জন্য উপস্থিত present জিডিআই + ব্রাশ ইত্যাদি আরও যুক্তিসঙ্গত, তবে এটি এমন পরিবেশে রিসোর্স ম্যানেজমেন্টের ক্ষেত্রে সত্যিই আরও বেশি কিছু যা আপনার পক্ষে এটি করতে পারে না - অন্তর্নিহিত এপিআই এবং / অথবা আপনার ভাষা / লাইব্রেরি / রানটাইমের অভাব।
লুয়ান

101

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

উদাহরণস্বরূপ, আসুন আমি বলি যে দুটি ক্যালেন্ডারের তারিখের মধ্যে আমাকে দিনের সংখ্যা গণনা করা দরকার যাতে আমি একটি ফাংশন তৈরি করি:

int daysBetween(Day a, Day b)

এটি করার জন্য, আমি তখন একটি নতুন ফাংশন তৈরি করি:

int daysSinceEpoch(Day day)

তারপরে আমার প্রথম ফাংশনটি সহজভাবে হয়ে যায়:

int daysBetween(Day a, Day b)
{
    return daysSinceEpoch(b) - daysSinceEpoch(a);
}

এ সম্পর্কে অ্যান্টি-প্যাটার্নের কিছুই নেই। দিনের মধ্যবর্তী প্যারামিটারগুলি অন্য পদ্ধতিতে পাঠানো হচ্ছে এবং পদ্ধতিতে কখনই রেফারেন্স করা হয় না তবে তাদের এখনও প্রয়োজন সেই পদ্ধতিটি করার জন্য এটি প্রয়োজন for

আমি যা প্রস্তাব করব তা প্রতিটি ফাংশনটি দেখে এবং কয়েকটি প্রশ্ন দিয়ে শুরু করা:

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

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

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


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

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

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

3
@ এসারুলম আমি মনে করি না এর জন্য একটি নাম আছে। এটি এমন একটি লক্ষণের মতো যা প্রচুর রোগের সাথে সাধারণ অ রোগের শর্ত যেমন 'শুকনো মুখ' এর মধ্যে সাধারণ। আপনি যদি কোডটির কাঠামোর বর্ণনাকে বের করে দেন তবে এটি নির্দিষ্ট কিছুতে নির্দেশ করতে পারে।
জিমি জেমস

@ এসারুলম এটি আপনাকে বলেছে যে এখানে কিছু ঠিক করার আছে - এটি এখন আরও স্পষ্ট। যে এর পরিবর্তে বৈশ্বিক পরিবর্তনশীল যখন কিছু ছিল তার চেয়ে স্থির করা উচিত।
ইমিগ্রিস

61

ববডালগাইশ ইতিমধ্যে উল্লেখ করেছে যে এই (বিরোধী) প্যাটার্নটিকে " ট্র্যাম্প ডেটা " বলা হয় ।

আমার অভিজ্ঞতা হিসাবে, অত্যধিক ট্র্যাম্প ডেটার সর্বাধিক সাধারণ কারণটিতে লিঙ্কযুক্ত স্টেট ভেরিয়েবলগুলির একটি গোছা রয়েছে যা সত্যই কোনও বস্তু বা কোনও ডেটা কাঠামোতে আবশ্যক। কখনও কখনও, তথ্য সঠিকভাবে সাজানোর জন্য এমনকি একগুচ্ছ বস্তুর বাসা বাঁধার প্রয়োজন হতে পারে।

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

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

playerName = "Bob"
playerEyeColor = GREEN
playerXPosition = -8
playerYPosition = 136
playerHealth = 100
playerMaxHealth = 100

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

mainGameLoop()
 -> processInputEvent()
     -> doPlayerAction()
         -> movePlayer()
             -> checkCollision()
                 -> interactWithNPC()
                     -> interactWithShopkeeper()

... এবং interactWithShopkeeper()ফাংশনটিতে দোকানের নামটি দিয়ে খেলোয়াড়কে সম্বোধন করা হয়েছে, সুতরাং আপনাকে এখন হঠাৎ এই সমস্ত ফাংশনটির playerNameমধ্য দিয়ে ট্র্যাম্প ডেটা হিসাবে পাস করতে হবে । এবং অবশ্যই, দোকানদার যদি মনে করেন যে নীল চোখের খেলোয়াড়গুলি নির্বোধ, এবং তাদের জন্য আরও দাম ধার্য করে, তবে আপনাকে পুরো ক্রিয়াকলাপের মধ্য দিয়ে যেতে হবে , ইত্যাদি।playerEyeColor

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

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

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

পরিবর্তে, সমাধানটি হ'ল বস্তুগুলির সাথে অন্য যে কোনও অবজেক্টের সাথে তাদের স্থায়ী বা অস্থায়ী সম্পর্ক রয়েছে সেগুলির উল্লেখ রয়েছে। সুতরাং, উদাহরণস্বরূপ, প্লেয়ার অবজেক্ট (এবং সম্ভবত কোনও এনপিসি অবজেক্টগুলিও) সম্ভবত "গেম ওয়ার্ল্ড" অবজেক্টের একটি রেফারেন্স সঞ্চয় করে রাখা উচিত, যার বর্তমান স্তরের / মানচিত্রের একটি রেফারেন্স থাকতে পারে, যাতে কোনও পদ্ধতির মতো player.moveTo(x, y)দরকার নেই প্যারামিটার হিসাবে স্পষ্টভাবে মানচিত্র দেওয়া হবে।

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

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


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

6
@ জিমি জেমস: পলিমারফিজম সম্পর্কে আপনার বক্তব্যটি একটি ভাল এবং আমি নিজেই এটি তৈরির বিষয়ে চিন্তাভাবনা করেছি, তবে উত্তরটি আরও দীর্ঘতর হতে না দেওয়ার জন্য এড়িয়ে গেছি। আমি যে বিন্দুটি (সম্ভবত খারাপভাবে) তৈরির চেষ্টা করছিলাম সেটি হ'ল, যদিও পুরোপুরি ডেটা প্রবাহের ক্ষেত্রে সামান্য পার্থক্য রয়েছে foo.method(bar, baz)এবং method(foo, bar, baz)অন্যান্য কারণ (পলিমারফিজম, এনক্যাপসুলেশন, স্থানীয়তা ইত্যাদি) এর সাথে পূর্ববর্তীটিকে পছন্দ করার জন্য রয়েছে।
ইলমারি করোনেন

@ ইলমারি কারোনেন: এটি খুব স্পষ্ট সুবিধা যে এটি ভবিষ্যতে যে কোনও পরিবর্তন / সংযোজন / মুছে ফেলা / বস্তুগুলির রিফ্যাক্টরিংগুলি (যেমন প্লেয়ারএজ) থেকে ফাংশন প্রোটোটাইপগুলি প্রমাণ করে। একা এটি অমূল্য।
smci

34

আমি এর নির্দিষ্ট নাম সম্পর্কে অবগত নই, তবে আমি অনুমান করি যে এটি উল্লেখ করা উচিত যে আপনি যে সমস্যাটি বর্ণনা করেছেন তা হ'ল এই জাতীয় প্যারামিটারের সুযোগের জন্য সেরা সমঝোতা খুঁজে পাওয়ার সমস্যা:

  • গ্লোবাল ভেরিয়েবল হিসাবে, প্রোগ্রামটি কোনও নির্দিষ্ট আকারে পৌঁছালে সুযোগটি খুব বড়

  • বিশুদ্ধরূপে স্থানীয় প্যারামিটার হিসাবে, সুযোগটি খুব ছোট হতে পারে, যখন এটি কল চেইনে প্রচুর পুনরাবৃত্তিমূলক প্যারামিটার তালিকাগুলি নিয়ে যায়

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


10
যথাযথ বর্গ নকশা জন্য +1। এটি ওও সমাধানের জন্য অপেক্ষা করা একটি ক্লাসিক সমস্যার মতো মনে হচ্ছে।
l0b0

21

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

আমিও @ JimmyJames এর উত্তর, যেখানে তিনি দাবী করেন যে এটা যে লাগে কালো বাক্স হিসাবে একে ফাংশন চিকিত্সা ভাল প্রোগ্রামিং অভ্যাস সঙ্গে একমত সব স্পষ্ট পরামিতি হিসেবে তার ইনপুট। এটি হ'ল আপনি যদি এমন কোনও ফাংশন লিখেন যা চিনাবাদাম মাখন এবং জেলি স্যান্ডউইচ তৈরি করে, আপনি এটি লিখতে পারেন

Sandwich make_sandwich() {
    PeanutButter pb = get_peanut_butter();
    Jelly j = get_jelly();
    return pb + j;
}
extern PhysicalRefrigerator g_refrigerator;
PeanutButter get_peanut_butter() {
    return g_refrigerator.get("peanut butter");
}
Jelly get_jelly() {
    return g_refrigerator.get("jelly");
}

তবে নির্ভরতা ইনজেকশন প্রয়োগ করা এবং এর পরিবর্তে এটি লিখতে ভাল অনুশীলন হবে:

Sandwich make_sandwich(Refrigerator& r) {
    PeanutButter pb = get_peanut_butter(r);
    Jelly j = get_jelly(r);
    return pb + j;
}
PeanutButter get_peanut_butter(Refrigerator& r) {
    return r.get("peanut butter");
}
Jelly get_jelly(Refrigerator& r) {
    return r.get("jelly");
}

এখন আপনার একটি ফাংশন রয়েছে যা স্পষ্টভাবে তার সমস্ত নির্ভরতাগুলি তার ফাংশন স্বাক্ষরে ডকুমেন্ট করে, যা পাঠযোগ্যতার জন্য দুর্দান্ত। সর্বোপরি, এটি সত্য যে make_sandwichআপনার জন্য একটি অ্যাক্সেস প্রয়োজন Refrigerator; সুতরাং পুরানো ফাংশন স্বাক্ষরটি মূলত ইনফুটগুলির অংশ হিসাবে রেফ্রিজারেটর গ্রহণ না করে নির্দোষ ছিল।

বোনাস হিসাবে, আপনি যদি আপনার ক্লাসের শ্রেণিবিন্যাসটি সঠিকভাবে করেন তবে টুকরো টুকরো টুকরো করা এড়িয়ে চলুন এবং এমন কি, আপনি make_sandwichপাসের মাধ্যমে ফাংশনটির ইউনিট-টেস্টও করতে পারেন MockRefrigerator! (আপনার এটিকে ইউনিট-টেস্ট করার প্রয়োজন হতে পারে কারণ আপনার ইউনিট-পরীক্ষার পরিবেশের কোনও অ্যাক্সেস নাও থাকতে পারে PhysicalRefrigerator))

আমি বুঝতে পারি যে নির্ভরতা ইনজেকশনের সমস্ত ব্যবহারের জন্য কল স্ট্যাকের নীচে একই রকমের প্যারামিটারের অনেক স্তরের প্লাম্বিংয়ের প্রয়োজন হয় না, তাই আপনি যে প্রশ্নটি জিজ্ঞাসা করেছিলেন আমি ঠিক তার উত্তর দিচ্ছি না ... তবে আপনি যদি এই বিষয়ে আরও পড়ার সন্ধান করছেন, "নির্ভরতা ইনজেকশন" অবশ্যই আপনার জন্য একটি প্রাসঙ্গিক কীওয়ার্ড।


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

8
@ দেবীমোরগান: স্পষ্টতই আপনি এটিকে সাধারণকরণ করতে , এমনকি "স্যান্ডউইচ" ধারণাকে সাধারণীকরণের Refrigeratorজন্য আরও চুল্লি তৈরি করতে পারেন ; এটিকে "জেনেরিক প্রোগ্রামিং" বলা হয় এবং এটি যুক্তিযুক্তভাবে শক্তিশালী, তবে ওপি সত্যই এই মুহুর্তে wantsুকতে চায় তার চেয়ে আরও বেশি উপায় রয়েছে। স্যান্ডউইচ প্রোগ্রামগুলির জন্য সঠিক স্তরের বিমূর্ততা সম্পর্কে একটি নতুন প্রশ্ন খোলামেলা দ্বিধা বোধ করুন। ;)IngredientSourcetemplate<typename... Fillings> StackedElementConstruction<Fillings...> make_sandwich(ElementSource&)
কুক্সপ্লসোন

11
কোনও ভুল না হয়, অনিবদ্ধ ব্যবহারকারীর অ্যাক্সেস থাকা উচিত নয়make_sandwich()
dotancohen

2
@ দেবী - এক্সকেসিডি লিঙ্ক
গ্যাভিন লক

19
আপনার কোডের সবচেয়ে গুরুতর ত্রুটি হ'ল আপনি ফ্রিজে চিনাবাদাম মাখন রাখছেন।
মালভোলিও

15

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


3
যদি level3()প্রয়োজন হয় newParamতবে তা নিশ্চিতভাবে মিলিত হচ্ছে তবে কোনওভাবে কোডের বিভিন্ন অংশকে একে অপরের সাথে যোগাযোগ করতে হবে। যদি সেই ফাংশনটি প্যারামিটারটি ব্যবহার করে তবে আমি অগত্যা কোনও ফাংশন প্যারামিটারকে খারাপ সংযুক্তি বলব না। আমি মনে করি চেন সমস্যাযুক্ত দিক অতিরিক্ত জন্য চালু কাপলিং level1()এবং level2()যার জন্য কোন ব্যবহার আছে newParamব্যতীত এটিতে পাস। উত্তম উত্তর, মিলনের জন্য +1।
নাল

6
@ নুল যদি তাদের সত্যিই এটির জন্য ব্যবহার না করা হয় তবে তারা তাদের কলারের কাছ থেকে গ্রহণের পরিবর্তে কোনও মূল্য তৈরি করতে পারে।
র্যান্ডম 832

3

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

আমি এই উত্তরগুলি থেকে সম্মত হলাম যা এই সমস্যাটি এড়াতে আরও ওও কিছু করার পরামর্শ দেয়। যাইহোক, " আপনি অনেক যুক্তি দিয়েছিলেন এমন একটি ক্লাসটি পাস করুন যেখানে আপনি কেবলমাত্র অনেক যুক্তি দিয়েছিলেন! " না ঝাঁপিয়েই এই তর্কগুলি গভীরভাবে হ্রাস করতে সহায়তা করার আরেকটি উপায় হ'ল রিফ্যাক্টর যাতে আপনার প্রক্রিয়াটির কয়েকটি পদক্ষেপ নীচের পরিবর্তে উচ্চ স্তরে ঘটে থাকে এক. উদাহরণস্বরূপ, কোডের আগে এখানে কিছু রয়েছে :

public void PerformReporting(StuffRepository repo, string desiredName) {
   var stuffs = repo.GetStuff(DateTime.Now());
   FilterAndReportStuff(stuffs, desiredName);
}

public void FilterAndReportStuff(IEnumerable<Stuff> stuffs, string desiredName) {
   var filter = CreateStuffFilter(FilterTypes.Name, desiredName);
   ReportStuff(stuffs.Filter(filter));
}

public void ReportStuff(IEnumerable<Stuff> stuffs) {
   stuffs.Report();
}

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

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

public void PerformReporting(StuffRepository repo, string desiredName) {
   var stuffs = repo.GetStuff(DateTime.Now());
   var filter = CreateStuffFilter(FilterTypes.Name, desiredName);
   var filteredStuffs = stuffs.Filter(filter)
   filteredStuffs.Report();
}

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

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

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

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

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


2

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


1
বিশদ সম্পর্কে কিছুটা দুর্বল, যা সম্ভবত ডাউনভোটগুলি ব্যাখ্যা করে। তবুও চেতনায় এই উত্তরটি হুবহু স্পষ্টভাবে রয়েছে: ওপি-র Demeter এর আইনটি পড়া উচিত - এটি প্রাসঙ্গিক শব্দ।
কনরাড রুডলফ

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

2
এই প্রশ্নের পরিস্থিতিটি ডেমিটারের আইনটির সাথে ঠিক কোনও সম্পর্কযুক্ত নয় ... পদ্ধতি কলগুলির শৃঙ্খলা সম্পর্কিত একটি পৃষ্ঠের মিল রয়েছে, তবে অন্যথায় এটি খুব আলাদা।
এরিক কিং

@Quuxplusone সম্ভাব্য, যদিও এই ক্ষেত্রে বিবরণ বেশ বিভ্রান্তিকর কারণ শৃঙ্খলিত কল সত্যিই যে দৃশ্যকল্প মধ্যে জানার জন্য না: তারা হবে নেস্টেড পরিবর্তে।
কনরাড রুডল্ফ

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

1

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

তবে, কেউ যদি ফাংশনাল প্রোগ্রামিং করে থাকে তবে ওপি কর্তৃক বর্ণিত পদ্ধতিটি খুব কার্যকর


0

এখানে মোটেও কোনও অ্যান্টি-প্যাটার্ন নেই, কারণ কলার নীচে এই সমস্ত স্তরের সম্পর্কে জানেন না এবং যত্নও করেন না।

কেউ উচ্চতর লেভেল (প্যারাম) কল করছেন এবং উচ্চতর লেভেলটি তার কাজটি করবে বলে প্রত্যাশা করে। প্যারামগুলির সাথে উচ্চতর লেভেল যা করে তা কলকারীদের ব্যবসায় নয়। উচ্চতর লেভেল সমস্যাটিকে সর্বোত্তম উপায়ে পরিচালনা করে, এক্ষেত্রে লেভেল 1 (প্যারাম) এ প্যারামগুলি পাস করে। একদম ঠিক আছে।

আপনি একটি কল চেইন দেখেন - তবে কোনও কল চেইন নেই। শীর্ষে একটি ফাংশন রয়েছে যার কাজটি এটি সেরা উপায়ে করতে পারে। এবং অন্যান্য কাজ আছে। প্রতিটি ফাংশন যে কোনও সময় প্রতিস্থাপন করা যেতে পারে।

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