নির্মাতা প্যাটার্ন: কখন ব্যর্থ হবে?


45

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

প্রথমে কিছু ব্যাখ্যা:

  • তাড়াতাড়ি ব্যর্থ হওয়ার সাথে সাথে আমি বলতে চাইছি যে কোনও অবৈধ প্যারামিটারটি প্রবেশের সাথে সাথে একটি অবজেক্ট তৈরি করা ব্যর্থ হওয়া উচিত So সুতরাং এর ভিতরে SomeObjectBuilder
  • দেরিতে ব্যর্থ হওয়ার সাথে সাথে আমি বলতে চাইছি যে কোনও অবজেক্ট তৈরি করা কেবলমাত্র সেই build()কলটিতে ব্যর্থ হতে পারে যা নিখুঁতভাবে অবজেক্টের একজন কনস্ট্রাক্টরকে বিল্ড করার জন্য ডাকে।

তারপরে কিছু যুক্তি:

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

এ সম্পর্কে সাধারণ ধারণা কী?


8
দেরিতে ব্যর্থ হওয়ার কোনও সুবিধা দেখছি না। কেউ একজন বিল্ডার শ্রেণিকে যা বলে "ভাল" ডিজাইনের চেয়ে অগ্রাধিকার গ্রহণ করে না, এবং বাগগুলি তাড়াতাড়ি ধরা দেরি করা দেরি করার চেয়ে সর্বদা ভাল।
ডোভাল

3
এটি দেখার আরেকটি উপায় হ'ল নির্মাতারা বৈধ ডেটা কী তা জানেন না। এই ক্ষেত্রে প্রথম দিকে ব্যর্থ হওয়া ত্রুটিযুক্ত হওয়া সম্পর্কে যত তাড়াতাড়ি আপনি জানেন যে ত্রুটি আছে। তাড়াতাড়ি ব্যর্থ না হওয়া, nullকোনও সমস্যা হলে বিল্ডার কোনও জিনিস ফেরত দেবেন build()
ক্রিস

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

উত্তর:


34

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

  1. বিল্ডারে সেটারগুলির ভিতরে।
  2. build()পদ্ধতির ভিতরে ।
  3. নির্মিত সত্তার অভ্যন্তরে: build()সত্তাটি তৈরি হওয়ার সময় এটি পদ্ধতিতে ডাকা হবে ।

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

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

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

সুতরাং, আমার দৃষ্টিকোণ থেকে, ডিজাইনের দৃষ্টিকোণ থেকে কেবল দেরি করে ফেলাই ভাল নয়, তবে বিল্ডার নিজেই নয় বরং নির্মাত্তর সত্তার ভিতরেই ব্যর্থ হওয়া আরও ভাল।

ইউপিডি: এই মন্তব্যটি আমাকে আরও একটি সম্ভাবনার কথা মনে করিয়ে দিয়েছে, যখন বিল্ডারের অভ্যন্তরে বৈধতা (বিকল্প 1 বা 2) বোঝায়। এটি নির্ধারণ করে না যদি নির্মাতার তৈরি করা বস্তুগুলির নিজস্ব চুক্তি করে। উদাহরণস্বরূপ, ধরে নিই যে আমাদের এমন একটি নির্মাতা আছেন যা নির্দিষ্ট বিষয়বস্তু দিয়ে একটি স্ট্রিং তৈরি করে, বলুন, সংখ্যা রেঞ্জের তালিকা 1-2,3-4,5-6। এই বিল্ডারের মতো পদ্ধতি থাকতে পারে addRange(int min, int max)। ফলস্বরূপ স্ট্রিং এই সংখ্যাগুলি সম্পর্কে কিছুই জানে না, এটিরও জানা উচিত নয়। নির্মাতা নিজেই স্ট্রিংয়ের বিন্যাস এবং সংখ্যার উপর সীমাবদ্ধতা নির্ধারণ করে। সুতরাং, পদ্ধতিটি addRange(int,int)অবশ্যই ইনপুট নম্বরগুলি বৈধ করে তুলবে এবং সর্বাধিক মিনিটের চেয়ে কম হলে একটি ব্যতিক্রম ছুঁড়ে ফেলতে হবে।

এটি বলেছিল, সাধারণ নিয়মটি কেবল বিল্ডার নিজেই নির্ধারিত চুক্তিগুলিকে বৈধতা দেবে।


আমি মনে করি যে এটি লক্ষণীয় যে বিকল্প 1 এর পরে "অসামঞ্জস্যপূর্ণ" পরীক্ষার সময় দেখা দিতে পারে, তবুও সবকিছু "যত তাড়াতাড়ি সম্ভব" হিসাবে সামঞ্জস্যপূর্ণ হিসাবে দেখা যেতে পারে। যদি এর পরিবর্তে নির্মাতা, স্টেপবিল্ডার এর রূপটি ব্যবহার করা হয় তবে "যত তাড়াতাড়ি সম্ভব" আরও সুনির্দিষ্ট করা আরও সহজ কিছুটা সহজ।
জোশুয়া টেলর

যদি কোনও ইউআরআই নির্মাতা যদি নাল স্ট্রিংটি পাস করে তবে একটি ব্যতিক্রম ছুঁড়ে ফেলে, এটি কি সলিডের লঙ্ঘন? আবর্জনা
গুডডর

@ গুডোর হ্যাঁ, যদি এটি নিজেই ব্যতিক্রম হয় th তবে ব্যবহারকারীর দৃষ্টিকোণ থেকে সমস্ত বিকল্প কোনও ব্যতিক্রমের মতো দেখতে কোনও বিল্ডার নিক্ষেপ করেছেন।
ইভান গামেল

তাহলে কেন একটি বৈধতা নেই (যা বিল্ড () দ্বারা ডাকা হয়? সেভাবে সামান্য নকল, ধারাবাহিকতা এবং কোনও এসআরপি লঙ্ঘন নেই। এটি নির্মাণের চেষ্টা না করে ডেটা বৈধকরণও সম্ভব করে তোলে এবং বৈধতা তৈরির কাছাকাছি।
স্টেলার ওয়ার্টেক্স

এই ক্ষেত্রে @ স্টারলারভর্টেক্সটি একবারে বিল্ডার.বিল্ড () এর মধ্যে একবার যাচাই করা হবে এবং যদি ডেটা বৈধ হয় এবং আমরা সেই কনস্ট্রাক্টরে অবজেক্টের কনস্ট্রাক্টরের দিকে এগিয়ে যাই।
ইভান গামেল

34

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

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

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

এই নিবন্ধটির সম্পাদকীয় ব্যাখ্যা অনুসারে নোট করুন, উপরের উদ্ধৃতিতে "আইটেমগুলি" কার্যকর জাভা, দ্বিতীয় সংস্করণে উপস্থাপিত বিধিগুলিকে বোঝায় ।

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

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

বিবেচনা করুন যে স্পোর্টস গাড়িতে 2 টিরও বেশি আসন থাকতে পারে না, setSeats(4)কেউ ঠিক আছে কিনা তা কীভাবে জানতে পারে ? এটি কেবল তখনই তৈরি হয় যখন কেউ নিশ্চিতভাবে জানতে পারে setSportsCar()যে আহ্বান করা হয়েছিল কি না, অর্থ নিক্ষেপ করা হবে কিনা TooManySeatsException


3
কোন ব্যতিক্রমটি নিক্ষেপ করতে হবে তার প্রস্তাব দেওয়ার জন্য, আমি কী খুঁজছিলাম।
Xantix

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

19

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

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

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

তবে এটি যে কোনও কিছুর চেয়ে সেরা অনুশীলন। আমি আশাকরি এটাই আপনার প্রশ্নের উত্তর।


11

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

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

আপনার যদি এমন পরিস্থিতিতে থাকার দুর্ভাগ্য হয় যেখানে কোনও গুনের বৈধতা অন্যের উপর নির্ভর করে, তবে আপনার দুটি পছন্দ আছে:

  • উভয় (বা আরও) বৈশিষ্ট্য একই সাথে সরবরাহ করা প্রয়োজন (যেমন একক পদ্ধতিতে প্রার্থনা)।
  • পরীক্ষার বৈধতা যত তাড়াতাড়ি আপনি জানেন যে আর কোনও পরিবর্তন আসবে না: কখন build()বা কখন ডাকা হয়।

বেশিরভাগ জিনিসের মতো এটিও একটি প্রসঙ্গে সিদ্ধান্ত নেওয়া। প্রসঙ্গটি যদি এটিকে প্রথমটিকে বিশ্রী বা জটিল করতে ব্যর্থ হয় তবে পরবর্তী সময়ে চেকগুলি স্থগিত করার জন্য একটি ট্রেড অফ করা যেতে পারে তবে ব্যর্থ-দ্রুতটি ডিফল্ট হওয়া উচিত।


সুতরাং সংক্ষিপ্তসার হিসাবে, আপনি বলছেন যে যত তাড়াতাড়ি সম্ভব কোনও জিনিস / আদিম ধরণে আচ্ছাদিত সমস্ত কিছু যাচাই করা যুক্তিসঙ্গত? লাইক unsigned, @NonNullইত্যাদি
স্কিভি

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

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

উদাহরণস্বরূপ, যদি একটি বিল্ডিং Shapeকরছে WithLeftএবং বিল্ডারের রয়েছে এবং তার WithRightবৈশিষ্ট্য রয়েছে এবং কোনও বিল্ডারকে আলাদা জায়গায় কোনও অবজেক্ট তৈরি করার জন্য সামঞ্জস্য করতে চান, যা প্রয়োজনের সাথে WithRightডানদিকে সরানোর সময় প্রথমে ডাকা হবে এবং WithLeftবাম দিকে সরানোর সময় অযথা জটিলতা যুক্ত করবে WithLeftপুরানো ডান প্রান্তের ডানদিকে বাম প্রান্তটি সেট করার অনুমতি দেওয়ার সাথে তুলনা করলে শর্ত থাকে যে ডাকা WithRightপ্রান্তটি buildডাকা হওয়ার আগে ঠিক করে দেয়।
সুপারক্যাট

0

প্রাথমিক নিয়মটি "তাড়াতাড়ি ব্যর্থ"।

সামান্য আরও উন্নত নিয়মটি "যত তাড়াতাড়ি সম্ভব ব্যর্থ"।

কোনও সম্পত্তি যদি অভ্যন্তরীণভাবে অবৈধ হয় ...

CarBuilder.numberOfWheels( -1 ). ...  

... তাহলে আপনি তা সঙ্গে সঙ্গে প্রত্যাখ্যান করবেন।

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

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