ব্যতিক্রম বা অপ্রয়োজনীয়তা ছাড়াই ইনপুট বৈধতা কীভাবে সম্পাদন করবেন


11

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

সুতরাং প্রায়শই যা ঘটে তা হ'ল আমি এই জাতীয় কোডের একটি টুকরো সম্পর্কে চিন্তা করেছি (এটি উদাহরণস্বরূপ কেবল উদাহরণ, জাভাতে এটি করা ফাংশনটি মনে করবেন না):

public static String padToEvenOriginal(int evenSize, String string) {
    if (evenSize % 2 == 1) {
        throw new IllegalArgumentException("evenSize argument is not even");
    }

    if (string.length() >= evenSize) {
        return string;
    }

    StringBuilder sb = new StringBuilder(evenSize);
    sb.append(string);
    for (int i = string.length(); i < evenSize; i++) {
        sb.append(' ');
    }
    return sb.toString();
}

ঠিক আছে, তাই বলুন যে evenSizeপ্রকৃতপক্ষে ব্যবহারকারীর ইনপুট থেকে প্রাপ্ত। সুতরাং আমি নিশ্চিত যে এটি এমনকি সমান। তবে আমি এই পদ্ধতিটি কল করতে চাই না এই সম্ভাবনাটি দিয়ে যে কোনও ব্যতিক্রম ছুঁড়েছে। সুতরাং আমি নিম্নলিখিত ফাংশন করা:

public static boolean isEven(int evenSize) {
    return evenSize % 2 == 0;
}

তবে এখন আমি দুটি চেক পেয়েছি যা একই ইনপুট বৈধতা সম্পাদন করে: ifবিবৃতিতে প্রকাশ এবং স্পষ্টত চেক ইন isEven। সদৃশ কোড, দুর্দান্ত নয়, তাই আসুন রিফ্যাক্টর:

public static String padToEvenWithIsEven(int evenSize, String string) {
    if (!isEven(evenSize)) { // to avoid duplicate code
        throw new IllegalArgumentException("evenSize argument is not even");
    }

    if (string.length() >= evenSize) {
        return string;
    }

    StringBuilder sb = new StringBuilder(evenSize);
    sb.append(string);
    for (int i = string.length(); i < evenSize; i++) {
        sb.append(' ');
    }
    return sb.toString();
}

ঠিক আছে, এটি সমাধান করেছে তবে এখন আমরা নিম্নলিখিত পরিস্থিতিতে into

String test = "123";
int size;
do {
    size = getSizeFromInput();
} while (!isEven(size)); // checks if it is even
String evenTest = padToEvenWithIsEven(size, test);
System.out.println(evenTest); // checks if it is even (redundant)

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

এখন isEvenঅবশ্যই সমস্যা তৈরি করে না, তবে প্যারামিটার চেকটি যদি আরও জটিল হয় তবে এটিতে খুব বেশি খরচ হতে পারে। এ ছাড়া, রিডান্ট্যান্ট কল করা ঠিক মনে হয় না simply

কখনও কখনও আমরা একটি "বৈধতাযুক্ত প্রকার" প্রবর্তন করে বা কোনও সমস্যা তৈরি করতে পারি যেখানে এই সমস্যাটি ঘটতে পারে না:

public static String padToEvenSmarter(int numberOfBigrams, String string) {
    int size = numberOfBigrams * 2;
    if (string.length() >= size) {
        return string;
    }

    StringBuilder sb = new StringBuilder(size);
    sb.append(string);
    for (int i = string.length(); i < size; i++) {
        sb.append('x');
    }
    return sb.toString();
}

তবে এর জন্য কিছু স্মার্ট চিন্তাভাবনা এবং বেশ বড় একটি চুল্লী প্রয়োজন।

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


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


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

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

কিন্তু, ব্যতিক্রম। রাইট?
রবার্ট হার্ভে

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

1
@ মার্টেনবোডওয়েস: আপনাকে মনে রাখতে হবে যে ব্যবহারকারীর ইনপুটটির বৈধতা কার্যকর padToEvenWithIsEven করে না । কলিং কোডে প্রোগ্রামিং ত্রুটি থেকে নিজেকে রক্ষা করতে এটি এর ইনপুটটিতে একটি বৈধতা যাচাই করে । এই বৈধতা কতটা প্রসারিত হওয়া দরকার তার উপর নির্ভর করে আপনি একটি খরচ / ঝুঁকি বিশ্লেষণের উপর নির্ভর করে যেখানে আপনি কলিং কোডটি লেখেন এমন ব্যক্তি ভুল পরামিতিতে পাস করার ঝুঁকির বিরুদ্ধে চেকের মূল্য রাখেন put
বার্ট ভ্যান ইনজেন শেনৌ

উত্তর:


7

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

public static String padString(int size, String string) {
    if (string.length() >= size) {
        return string;
    }

    StringBuilder sb = new StringBuilder(size);
    sb.append(string);
    for (int i = string.length(); i < size; i++) {
        sb.append(' ');
    }
    return sb.toString();
}

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

final class EvenInteger {
  public final int value;

  public EvenInteger(int value) {
    if (!(value % 2 == 0))
      throw new IllegalArgumentException("EvenInteger(" + value + ") is not even");
    this.value = value;
  }
}

এখন আপনি ঘোষণা করতে পারেন

public static String padStringToEven(EvenInteger evenSize, String string)
    ...

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

এ জাতীয় ক্ষুদ্রতর প্রকারের ব্যবহার এমনকি কার্যকর হতে পারে এমনকি যখন তারা কোনও বৈধতা না করে, যেমন একটি FirstNameথেকে একটি প্রতিনিধিত্ব করে একটি স্ট্রিং বিচ্ছিন্ন করা LastName। আমি প্রায়শই এই প্যাটার্নটি স্থিরভাবে টাইপ করা ভাষায় ব্যবহার করি।


আপনার দ্বিতীয় কার্যটি এখনও কিছু ক্ষেত্রে ব্যতিক্রম ছুঁড়ে না?
রবার্ট হার্ভে

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

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

1
@ মার্টেনবোডওয়েস যদি আপনি বৈধতা করতে চান তবে আপনি ব্যতিক্রমের মতো কিছু থেকে মুক্তি পেতে পারেন না। ঠিক আছে, বিকল্পটি হ'ল স্থির ফাংশন ব্যবহার করা যা কোনও বৈধতা প্রাপ্ত বস্তুটি দেয় বা ব্যর্থতা বাতিল করে, তবে এর মূলত কোনও সুবিধা নেই। তবে বৈধতাটি ফাংশনটির বাইরে কনস্ট্রাক্টারে স্থানান্তরিত করে আমরা এখন বৈধতা ত্রুটির সম্ভাবনা ছাড়াই ফাংশনটি কল করতে পারি। যা কলকারীকে সমস্ত নিয়ন্ত্রণ দেয়। উদাহরণ:EvenInteger size; while (size == null) { try { size = new EvenInteger(getSizeFromInput()); } catch(...){}} String result = padStringToEven(size,...);
আমন

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

9

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

public final class EvenInteger {
    private final int value;

    private EvenInteger(value) {
        this.value = value;
    }

    public static Optional<EvenInteger> of(final int value) {
        if (value % 2 == 0) {
            return Optional.of(new EvenInteger(value));
        }
        return Optional.empty();
    }

    public int getValue() {
        return this.value;
    }
}

এরপরে আমরা সহজেই Optionalইনপুট যুক্তি লেখার জন্য মানক পদ্ধতিগুলি ব্যবহার করতে পারি :

class GetEvenInput {
    public Optional<EvenInteger> askOnce() {
        int size = getSizeFromInput();
        return EvenInteger.of(size);
    }

    public EvenInteger keepAsking() {
        return askOnce().orElseGet(() -> keepAsking());
    }
}

আপনি keepAsking()ডু-ওয়েল লুপের মাধ্যমে আরও মুদ্রিত জাভা শৈলীতে লিখতেও পারেন।

Optional<EvenInteger> result;
do {
    result = askOnce();
} while (!result.isPresent());

return result.get();

তারপর আপনার কোড বাকি আপনি উপর নির্ভর করতে পারেন EvenIntegerনিশ্চয়তা এটি সত্যিই এমনকি হতে হবে এবং আমাদের তা পরীক্ষা শুধুমাত্র কখনও একবার লেখা হয়েছিল, সঙ্গে EvenInteger::of


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

1

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

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

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


ওপিতে উল্লেখ করা হয়েছে যে ফাংশন ছোঁড়া রোধ করতে ইনপুট বৈধতা করা হয়। সুতরাং চেকগুলি সম্পূর্ণ নির্ভরশীল এবং ইচ্ছাকৃতভাবে একই।
ডি Drmmr

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