এমন কোনও নির্মাণকারী যা তার যুক্তিগুলিকে বৈধতা দেয় তা এসআরপি লঙ্ঘন করে?


66

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

উদাহরণস্বরূপ, কোনও কনস্ট্রাক্টরের ইনপুট পরীক্ষা করতে, আমি নিম্নলিখিত পদ্ধতিটি চালু করতে পারি ( Streamইনপুটটি এলোমেলো, কিছু হতে পারে)

private void CheckInput(Stream stream)
{
    if(stream == null)
    {
        throw new ArgumentNullException();
    }

    if(!stream.CanWrite)
    {
        throw new ArgumentException();
    }
}

এই পদ্ধতিটি (তর্কযুক্ত) একাধিক জিনিস করে

  • ইনপুটগুলি পরীক্ষা করুন
  • বিভিন্ন ব্যতিক্রম নিক্ষেপ

এসআরপি মেনে চলার জন্য আমি যুক্তিটি পরিবর্তিত করেছি

private void CheckInput(Stream stream, 
                        params (Predicate<Stream> predicate, Action action)[] inputCheckers)
{
    foreach(var inputChecker in inputCheckers)
    {
        if(inputChecker.predicate(stream))
        {
            inputChecker.action();
        }
    }
}

যা অনুমানযোগ্যভাবে কেবল একটি কাজ করে (তা করে?): ইনপুটটি পরীক্ষা করে দেখুন। ইনপুটগুলির প্রকৃত চেক করার জন্য এবং ব্যতিক্রমগুলি ছুঁড়ে দেওয়ার জন্য আমি যেমন পদ্ধতিগুলি চালু করেছি

bool StreamIsNull(Stream s)
{
    return s == null;
}

bool StreamIsReadonly(Stream s)
{
    return !s.CanWrite;
}

void Throw<TException>() where TException : Exception, new()
{
    throw new TException();
}

এবং কল করতে CheckInputপারেন

CheckInput(stream,
    (this.StreamIsNull, this.Throw<ArgumentNullException>),
    (this.StreamIsReadonly, this.Throw<ArgumentException>))

এটি কি আদৌ প্রথম বিকল্পের চেয়ে ভাল, বা আমি অযৌক্তিক জটিলতার পরিচয় দেব? আমি এখনও এই প্যাটার্নটি উন্নত করতে পারি এমন কোনও উপায় আছে, যদি তা আদৌ কার্যকর হয়?


26
আমি তর্ক করতে পারি যে CheckInputএখনও একাধিক কাজ করছে: এটি উভয়ই একটি অ্যারের মাধ্যমে পুনরাবৃত্তি হয় এবং একটি প্রাকটিক ফাংশন কল করে এবং একটি ক্রিয়া ফাংশন কল করে। তাও কি এসআরপি লঙ্ঘন নয়?
বার্ট ভ্যান ইনজেন শেহেনো

8
হ্যাঁ, এটিই আমি তৈরি করার চেষ্টা করছিলাম।
বার্ট ভ্যান ইনজেন শেহেনো

135
এটি মনে রাখা গুরুত্বপূর্ণ যে এটি একক দায়িত্বের নীতি; একক কর্ম নীতি নয়। এটির একটি দায়িত্ব রয়েছে: প্রবাহটি সংজ্ঞায়িত ও লিখিতযোগ্য যাচাই করুন।
ডেভিড আরনো

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

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

উত্তর:


151

এসআরপি সম্ভবত সবচেয়ে ভুল বুঝে নেওয়া সফ্টওয়্যার নীতি।

একটি সফ্টওয়্যার অ্যাপ্লিকেশন মডিউলগুলি থেকে তৈরি করা হয়, যা মডিউলগুলি থেকে নির্মিত হয়, যা থেকে নির্মিত ...

নীচে, একটি একক ফাংশন যেমন CheckInputকেবলমাত্র যুক্তিযুক্ত একটি সামান্য বিট থাকবে, কিন্তু আপনি উপরের দিকে যেতে প্রতিটি ক্রমাগত মডিউল আরও এবং আরও যুক্তি encapsulate এবং এটি স্বাভাবিক

এসআরপি কোনও একক পারমাণবিক ক্রিয়া করার কথা নয়। এটির একটি একক দায়িত্ব থাকা সম্পর্কে, এমনকি যদি সেই দায়িত্বটির একাধিক ক্রিয়া প্রয়োজন ... এবং শেষ পর্যন্ত এটি রক্ষণাবেক্ষণ এবং পরীক্ষার যোগ্যতা সম্পর্কে :

  • এটি এনক্যাপসুলেশনকে প্রচার করে (Obশ্বরের বিষয়গুলি এড়ানো),
  • এটি উদ্বেগের বিচ্ছেদকে উত্সাহ দেয় (পুরো কোডবেজের মাধ্যমে পরিবর্তনগুলি এড়ানো),
  • এটি দায়িত্বের পরিধি সংকুচিত করে টেস্টাবিলিটিকে সহায়তা করে।

সত্য যে CheckInputদুই চেক সঙ্গে বাস্তবায়িত দুটি ভিন্ন ব্যতিক্রম বাড়াতে হয় অপ্রাসঙ্গিক কিছুটা হলেও।

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

আসুন তুলনা করা যাক:

Constructor(Stream stream) {
    CheckInput(stream);
    // ...
}

বনাম:

Constructor(Stream stream) {
    CheckInput(stream,
        (this.StreamIsNull, this.Throw<ArgumentNullException>),
        (this.StreamIsReadonly, this.Throw<ArgumentException>));
    // ...
}

এখন, CheckInputকম করে ... তবে তার কলার আরও কিছু করে!

আপনি প্রয়োজনীয়তার তালিকাটি এখান থেকে সরিয়ে নিয়েছেন CheckInput, সেগুলি যেখানে এনক্যাপুলেটেড রয়েছে, Constructorযেখানে সেগুলি দৃশ্যমান।

এটা কি ভাল পরিবর্তন? এটা নির্ভর করে:

  • যদি CheckInputকেবল সেখানে বলা হয়: এটি বিতর্কযোগ্য, একদিকে এটি প্রয়োজনীয়তাগুলিকে দৃশ্যমান করে তোলে, অন্যদিকে কোডটি বিশৃঙ্খল করে তোলে;
  • যদি একই প্রয়োজনীয়তার সাথেCheckInput একাধিকবার ডাকা হয় , তবে এটি ডিআরওয়াই লঙ্ঘন করে এবং আপনার একটি এনক্যাপসুলেশন সমস্যা রয়েছে।

এটি উপলব্ধি করা গুরুত্বপূর্ণ যে একটি একক দায়বদ্ধতা অনেক কাজকে বোঝায় । স্ব-ড্রাইভিং গাড়ির "মস্তিষ্ক" এর একক দায়িত্ব থাকে:

গাড়িটিকে তার গন্তব্যে চালাচ্ছি।

এটি একক দায়িত্ব, তবে প্রচুর সিদ্ধান্ত গ্রহণ এবং একাধিক সেন্সর এবং অভিনেতা সমন্বয়ের প্রয়োজন, এমনকি সম্ভবত বিবাদমান প্রয়োজনীয়তাও রয়েছে ...

... তবে, এটি সমস্ত encapsulated। সুতরাং ক্লায়েন্ট যত্ন নেই।

যাত্রীদের 1 সুরক্ষা, অন্যের সুরক্ষা, নিয়মের সম্মান, ...


2
আমি মনে করি আপনি "এনক্যাপসুলেশন" শব্দটি ব্যবহার করছেন এবং এর ডেরাইভেটিভগুলি বিভ্রান্তিকর। তা ছাড়া আর দুর্দান্ত উত্তর!
ফ্যাবিও তুরতি

4
আমি আপনার উত্তরের সাথে একমত, কিন্তু স্ব-ড্রাইভিং গাড়ির মস্তিষ্ক যুক্তি প্রায়ই লোকদের এসআরপি ভাঙতে প্ররোচিত করে। যেমনটি আপনি বলেছেন, এটি মডিউলগুলি মডিউলগুলি দিয়ে তৈরি মডিউলগুলি। আপনি পুরো সিস্টেমটির উদ্দেশ্যটি সনাক্ত করতে পারেন, তবে সেই সিস্টেমটিকে নিজেরাই ভেঙে ফেলা উচিত । আপনি প্রায় যে কোনও সমস্যা ভেঙে ফেলতে পারেন।
সাভা বি

13
@ সাবাব: অবশ্যই, তবে নীতিটি একই রয়েছে। মডিউলটির একক দায়িত্ব থাকতে হবে যদিও এর উপাদানগুলির চেয়ে বৃহত্তর সুযোগ রয়েছে।
ম্যাথিউ এম।

3
@ user949300 ঠিক আছে, কীভাবে ঠিক "ড্রাইভিং" করা যায়। সত্যই, "ড্রাইভিং" দায়বদ্ধতা এবং "সুরক্ষিতভাবে" এবং "আইনীভাবে" এটি সেই দায়িত্বটি কীভাবে সম্পাদন করে সে সম্পর্কে প্রয়োজনীয়তা। এবং একটি দায়িত্ব উল্লেখ করার সময় আমরা প্রায়শই প্রয়োজনীয়তাগুলি তালিকাভুক্ত করি।
ব্রায়ান ম্যাকচ্যাটন

1
"এসআরপি হ'ল সম্ভবত সবচেয়ে ভুল বুঝে নেওয়া সফ্টওয়্যার নীতি" " এই উত্তর দ্বারা প্রমাণ হিসাবে :)
মাইকেল 8

41

এসআরপি সম্পর্কে আঙ্কেল ববকে উদ্ধৃত করা ( https://8thlight.com/blog/uncle-bob/2014/05/08/SingleReponsibilityPr صولle.html ):

একক দায়িত্বের নীতি (এসআরপি) বলেছে যে প্রতিটি সফ্টওয়্যার মডিউলের পরিবর্তনের একটি এবং একমাত্র কারণ থাকতে হবে।

... এই নীতিটি মানুষের সম্পর্কে।

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

... এই কারণেই আমরা জেএসপিগুলিতে এসকিউএল রাখি না। এই কারণেই আমরা মডিউলগুলিতে এইচটিএমএল তৈরি করি না যা ফলাফলগুলি গণনা করে। এই কারণেই ব্যবসায়ের নিয়মগুলি ডাটাবেস স্কিমাটি জানা উচিত নয়। এই কারণেই আমরা উদ্বেগকে আলাদা করি।

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

এটি কি আদৌ প্রথম বিকল্পের চেয়ে ভাল, বা আমি অযৌক্তিক জটিলতার পরিচয় দেব? আমি এখনও এই প্যাটার্নটি উন্নত করতে পারি এমন কোনও উপায় আছে, যদি তা আদৌ কার্যকর হয়?

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


4
সেরা উত্তর. ও.পি. সম্পর্কে বিস্তারিত জানার জন্য, যদি গার্ডের চেকগুলি দুটি পৃথক স্টেকহোল্ডার / বিভাগ থেকে আসে, তবে checkInputs()বিভক্ত হওয়া উচিত, checkMarketingInputs()এবং বলুন checkRegulatoryInputs()। অন্যথায় এটি সমস্ত পদ্ধতিকে এক পদ্ধতিতে একত্রিত করা ভাল।
user949300

36

না, এই পরিবর্তনটি এসআরপি দ্বারা অবহিত করা হয়নি।

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

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

কোনও পদ্ধতিতে প্রকার স্থাপন করা একক দায়িত্বের নীতি লঙ্ঘন নয়; না পদ্ধতিটি পূর্ব শর্তগুলি কার্যকর করছে বা এর পোস্টকন্ডিশন জোর করছে না।


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

23

সমস্ত দায়িত্ব সমানভাবে তৈরি করা হয় না।

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

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

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

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

একটি জিনিসের একক দায়িত্ব থাকার অর্থ এই নয় যে এখানে কেবলমাত্র একটি জিনিস ঘটতে পারে। দায়িত্ব বাসা বাঁধতে পারে। তবে বাসা বাঁধার এই দায়িত্বগুলি বোঝা উচিত, আপনি যখন তাদের এখানে পাবেন তখন আপনাকে অবাক করে দেওয়া উচিত নয় এবং যদি সেগুলি চলে যায় তবে আপনি তাদের মিস করবেন।

সুতরাং যখন আপনি অফার

CheckInput(Stream stream);

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


21

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

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

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

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


14

চেক ইনপুট ভূমিকা

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

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

বৈধতা পরীক্ষা

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

উপসংহার

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


4

নীতিটি দৃhat়তার সাথে কোনও কোডের টুকরোটিকে "কেবলমাত্র একটি কাজই" করা উচিত নয়।

এসআরপিতে "দায়িত্বশীলতা" প্রয়োজনীয়তার স্তরে বোঝা উচিত। কোডের দায়িত্ব ব্যবসায়ের প্রয়োজনীয়তা পূরণ করা। যদি কোনও বস্তু একাধিক স্বতন্ত্র ব্যবসায়ের প্রয়োজনীয়তা পূরণ করে তবে এসআরপি লঙ্ঘিত হয় । স্বতন্ত্রভাবে এর অর্থ হ'ল একটি প্রয়োজনীয়তা পরিবর্তিত হতে পারে যখন অন্য প্রয়োজনীয়তা স্থির থাকে।

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

এসআরপি লঙ্ঘনের প্রকৃত উদাহরণটি এই জাতীয় কোড হবে:

var message = "Your package will arrive before " + DateTime.Now.AddDays(14);

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


কার্যত প্রতিটি প্রয়োজনের জন্য একটি পৃথক শ্রেণি এক অপরিচ্ছন্ন দুঃস্বপ্নের মতো শোনাচ্ছে।
হোসনেম

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

আমি মনে করি এটি আরও বেশি যে এসআরপি-র পরিস্থিতিগত বিচারের একটি উপাদান প্রয়োজন যা একক আকর্ষণীয় বাক্যাংশে বর্ণনা করা চ্যালেঞ্জক।
হোসনেম

@ ওয়াটসিসনাম: আমি সম্পূর্ণ একমত
জ্যাকবিবি

যদি কোনও বস্তু একাধিক স্বতন্ত্র ব্যবসায়ের প্রয়োজনীয়তা পূরণ করে তবে এসআরপির
জুজার আলী

3

আমি @ এরিকলিপার্টের উত্তর থেকে পয়েন্টটি পছন্দ করি :

নিজেকে জিজ্ঞাসা করুন কেন আপনার চেকারে চেক নেই কেন সেই বস্তুটির জন্য যা একটি স্ট্রিম । উত্তরটি সুস্পষ্ট: ভাষা কলকারীকে এমন একটি প্রোগ্রাম সংকলন থেকে বাধা দেয় যা একটি অ-স্ট্রিমে যায়।

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

এরিকলিপার্টের ঠিক যে এটি টাইপ সিস্টেমের জন্য একটি সমস্যা। এবং যেহেতু আপনি একক-দায়িত্ব নীতি (এসআরপি) ব্যবহার করতে চান, সুতরাং আপনার মূলত এই কাজের জন্য দায়বদ্ধ হওয়ার জন্য টাইপ সিস্টেমের প্রয়োজন।

সি # তে এটি করা বাছাই করা আসলে সম্ভব। আমরা nullসংকলনের সময় আক্ষরিক ধরতে পারি , তারপরে nullরান-টাইমে অ-আক্ষরিককে ধরতে পারি । এটি একটি সম্পূর্ণ সংকলন-সময় চেক হিসাবে ভাল নয়, তবে এটি সংকলন-সময়ে কখনই ধরা না দেওয়ার চেয়ে কঠোর উন্নতি।

তো, তুমি জানো কীভাবে # # আছে Nullable<T>? এর বিপরীত এবং একটি করা যাক NonNullable<T>:

public struct NonNullable<T> where T : class
{
    public T Value { get; private set; }
    public NonNullable(T value)
    {
        if (value == null) { throw new NullArgumentException(); }
        this.Value = value;
    }
    //  Ease-of-use:
    public static implicit operator T(NonNullable<T> value) { return value.Value; }
    public static implicit operator NonNullable<T>(T value) { return new NonNullable<T>(value); }

    //  Hack-ish overloads that prevent null-literals from being implicitly converted into NonNullable<T>'s.
    public static implicit operator NonNullable<T>(Tuple<T> value) { return new NonNullable<T>(value.Item1); }
    public static implicit operator NonNullable<T>(Tuple<T, T> value) { return new NonNullable<T>(value.Item1); }
}

এখন লেখার বদলে

public void Foo(Stream stream)
{
  if (stream == null) { throw new NullArgumentException(); }

  // ...method code...
}

, শুধু লেখো:

public void Foo(NonNullable<Stream> stream)
{
  // ...method code...
}

তারপরে, তিনটি ব্যবহারের কেস রয়েছে:

  1. Foo()নন-নাল সহ ব্যবহারকারী কলগুলি Stream:

    Stream stream = new Stream();
    Foo(stream);

    এটি হ'ল কাঙ্ক্ষিত ব্যবহারের কেস, এবং এটি-বা-ছাড়া কাজ করে NonNullable<>

  2. Foo()নাল দিয়ে ব্যবহারকারী কলগুলি Stream:

    Stream stream = null;
    Foo(stream);

    এটি একটি কলিং ত্রুটি। এখানে NonNullable<>ব্যবহারকারীকে জানাতে সহায়তা করে যে তাদের এটি করা উচিত নয়, তবে এটি আসলে তাদের থামায় না। যেভাবেই হোক, এটি রান-টাইমের ফলাফল NullArgumentException

  3. ব্যবহারকারী কল Foo()সঙ্গে null:

    Foo(null);

    nullসুস্পষ্টভাবে একটিতে রূপান্তরিত হবে না NonNullable<>, তাই ব্যবহারকারী রান- টাইমের আগে আইডিইতে ত্রুটি পায় । এটি টাইপ সিস্টেমে নাল চেকের দায়িত্ব দিচ্ছে, যেমনটি এসআরপি পরামর্শ দেবে।

আপনার যুক্তি সম্পর্কে অন্যান্য জিনিসও জোর দেওয়ার জন্য আপনি এই পদ্ধতিটি প্রসারিত করতে পারেন। উদাহরণস্বরূপ, যেহেতু আপনি একটি লিখনযোগ্য স্ট্রিম চান, আপনি একটি নির্ধারণ করতে পারেন যা struct WriteableStream<T> where T:Streamউভয় nullএবং stream.CanWriteকনস্ট্রাক্টরের জন্য যাচাই করে। এটি এখনও একটি রান-টাইম টাইপ চেক হবে, তবে:

  1. এটি WriteableStreamকোয়ালিফায়ারের সাথে প্রকারটি সজ্জিত করে , কলকারীদের প্রয়োজনীয়তার সংকেত দেয়।

  2. এটি কোডে এক জায়গায় চেক করে, তাই আপনাকে throw InvalidArgumentExceptionপ্রতিটি বার চেকটি পুনরাবৃত্তি করতে হবে না ।

  3. এটি টাইপ সিস্টেমে টাইপ-চেকিং শুল্কগুলি (জেনেরিক সাজসজ্জার দ্বারা প্রসারিত হিসাবে) চাপিয়ে আরও ভালভাবে এসআরপিকে সম্মতি জানায়।


3

আপনার পদ্ধতির বর্তমানে পদ্ধতিগত। আপনি Streamঅবজেক্টটি ভেঙে বাইরে থেকে যাচাই করছেন। এটি করবেন না - এটি এনক্যাপসুলেশনটি ভেঙে দেয়। Streamএর নিজস্ব বৈধতার জন্য দায়বদ্ধ হতে দিন । এসআরপি প্রয়োগ করার জন্য কিছু ক্লাস না পাওয়া পর্যন্ত আমরা প্রয়োগ করতে চাই না classes

এখানে Streamযা কোনও ক্রিয়া সম্পাদন করে কেবল যদি তা বৈধতা পাস করে:

class Stream
{
    public void someAction()
    {
        if(!stream.canWrite)
        {
            throw new ArgumentException();
        }

        System.out.println("My action");
    }
}

তবে এখন আমরা এসআরপি লঙ্ঘন করছি! "একটি শ্রেণীর পরিবর্তনের একমাত্র কারণ থাকতে হবে।" আমরা 1) বৈধতা এবং 2) প্রকৃত যুক্তি মিশ্রণ পেয়েছি। এটির পরিবর্তনের প্রয়োজন হতে পারে এমন দুটি কারণ আমরা পেয়েছি।

আমরা বৈধকরণের সজ্জকারদের সাথে এটি সমাধান করতে পারি । প্রথমত, আমাদের আমাদের Streamএকটি ইন্টারফেসে রূপান্তর করতে হবে এবং এটি একটি কংক্রিট শ্রেণি হিসাবে প্রয়োগ করতে হবে।

interface Stream
{
    void someAction();
}

class DefaultStream implements Stream
{
    @Override
    public void someAction()
    {
        System.out.println("My action");
    }
}

আমরা এখন একটি সাজসজ্জা লিখতে পারি যা একটিকে মোড়ানো Stream, কার্যকারিতা সম্পাদন করে এবং Streamক্রিয়াটির আসল যুক্তির জন্য প্রদত্তকে ডিফার করে ।

class WritableStream implements Stream
{
    private final Stream stream;

    public WritableStream(final Stream stream)
    {
        this.stream = stream;
    }

    @Override
    public void someAction()
    {
        if(!stream.canWrite)
        {
            throw new ArgumentException();
        }
        stream.someAction();
    }
}

আমরা এখন আমাদের যেকোন উপায়ে এটি রচনা করতে পারি:

final Stream myStream = new WritableStream(
    new DefaultStream()
);

অতিরিক্ত বৈধতা চান? অন্য সজ্জা যুক্ত করুন।


1

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

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

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


0

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

সিউডো কোডের দুর্বল উদাহরণটি দেখে নেওয়া যাক।

class Math
    private int a;
    private int b;
    def constructor(int x, int y) 
        if(x != null)
          a = x
        else if(x < 0)
          a = abs(x)
        else if (x == -1)
          throw "Some Silly Error"
        else
          a = 0
        end
        if(y != null)
           b = y
        else if(y < 0)
           b = abs(y)
        else if(y == -1)
           throw "Some Silly Error"
        else
         b = 0
        end
    end
    def add()
        return a + b
    end
    def sub()
        return b - a
    end
end

আমাদের বরং অযৌক্তিক উদাহরণে গণিতের অবজেক্টকে ব্যবহারযোগ্য করে তোলা ম্যাথ # কনস্ট্রাক্টরের "দায়িত্ব"। এটি প্রথমে ইনপুটটি স্যানিটাইজ করে, তারপরে মানগুলি -1 হয় না তা নিশ্চিত করে তা করে।

এটি বৈধ এসআরপি কারণ কনস্ট্রাক্টর কেবল একটি কাজ করছে। এটি ম্যাথ অবজেক্ট প্রস্তুত করছে। তবে এটি খুব রক্ষণাবেক্ষণযোগ্য নয়। এটি ডিআরওয়াই লঙ্ঘন করে।

সুতরাং এটি অন্য পাস নিতে দিন

class Math
    private int a;
    private int b;
    def constructor(int x, int y)
        cleanX(x)
        cleanY(y)
    end
    def cleanX(int x)
        if(x != null)
          a = x
        else if(x < 0)
          a = abs(x)
        else if (x == -1)
          throw "Some Silly Error"
        else
          a = 0
        end
   end
   def cleanY(int y)
        if(y != null)
           b = y
        else if(y < 0)
           b = abs(y)
        else if(y == -1)
           throw "Some Silly Error"
        else
         b = 0
        end
    end
    def add()
        return a + b
    end
    def sub()
        return b - a
    end
end

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

এটি আবার যেতে দিন

class Math
    private int a;
    private int b;
    def constructor(int x, int y)
        a = clean(x)
        b = clean(y)
    end
    def clean(int i)
        if(i != null)
          return i
        else if(i < 0)
          return abs(i)
        else if (i == -1)
          throw "Some Silly Error"
        else
          return 0
        end
    end
    def add()
        return a + b
    end
    def sub()
        return b - a
    end
end

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

কোডটি তাত্ত্বিকভাবে আরও রক্ষণাবেক্ষণযোগ্য এবং আরও ভাল এখনও আমরা যখন বাগটি ঠিক করতে এবং কোডটি আরও শক্ত করতে যাই, আমাদের কেবল এটি এক জায়গায় করা দরকার।

class Math
    private int a;
    private int b;
    def constructor(int x, int y)
        a = clean(x)
        b = clean(y)
    end
    def clean(int i)
        if(i == null)
          return 0
        else if (i == -1)
          throw "Some Silly Error"
        else
          return abs(i)
        end
    end
    def add()
        return a + b
    end
    def sub()
        return b - a
    end
end

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


-3

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

ক্লাসিংয়ের কোডিংয়ে বিশেষত পরীক্ষাগুলিতে ফোলাভাবের প্রশ্নে ফলাফলের ক্লাসের সম্মিলিততার আশ্বাস না দিয়েই কনস্ট্রাক্টর প্যারামিটারগুলির অ-বাতিলকরণ কার্যকর করা।

আপনি যদি সত্যিই এই জাতীয় চুক্তিগুলি প্রয়োগ করতে চান তবে Debug.Assertবিশৃঙ্খলা হ্রাস করার জন্য ব্যবহার করা বা এর অনুরূপ কিছু বিবেচনা করুন :

public AClassThatDefinitelyNeedsAWritableStream(Stream stream)
{
   Assert.That(stream.CanWrite, "Put crucial information here, and not inane bloat.");

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