অযৌক্তিক ডিফল্ট মান সহ কাঠামো


12

আমার সিস্টেম আমি ঘন ঘন বিমানবন্দর কোড (চালিত "YYZ", "LAX", "SFO", ইত্যাদি), তারা সঠিক একই বিন্যাস (3 অক্ষর বড় হাতের হিসাবে প্রতিনিধিত্ব) এ সবসময়। সিস্টেমটি সাধারণত এপিআই অনুরোধে এই (পৃথক) কোডগুলির 25-50 এর সাথে সম্পর্কিত হয়, মোট এক হাজারেরও বেশি বরাদ্দ সহ, তারা আমাদের অ্যাপ্লিকেশনটির অনেক স্তর দিয়ে যায় এবং প্রায়শই সাম্যের জন্য তুলনা করা হয়।

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

এটি থেকে, আমি কাছাকাছি স্ট্রিংগুলি বন্ধ করা এবং একটি Airportক্লাস তৈরি করার সিদ্ধান্ত নিয়েছি , যার একটি একক নির্মাতা রয়েছে যা বিমানবন্দর কোডটি গ্রহণ করে এবং বৈধ করে।

public sealed class Airport
{
    public Airport(string code)
    {
        if (code == null)
        {
            throw new ArgumentNullException(nameof(code));
        }

        if (code.Length != 3 || !char.IsLetter(code[0]) 
        || !char.IsLetter(code[1]) || !char.IsLetter(code[2]))
        {
            throw new ArgumentException(
                "Must be a 3 letter airport code.", 
                nameof(code));
        }

        Code = code.ToUpperInvariant();
    }

    public string Code { get; }

    public override string ToString()
    {
        return Code;
    }

    private bool Equals(Airport other)
    {
        return string.Equals(Code, other.Code);
    }

    public override bool Equals(object obj)
    {
        return obj is Airport airport && Equals(airport);
    }

    public override int GetHashCode()
    {
        return Code?.GetHashCode() ?? 0;
    }

    public static bool operator ==(Airport left, Airport right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Airport left, Airport right)
    {
        return !Equals(left, right);
    }
}

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

আমি যে জিনিসটি লক্ষ্য করেছি, তা হ'ল আবর্জনা সংগ্রহের কাজটি প্রায়শই চলছিল যা আমি Airportসংগ্রহ করার ঘটনাগুলিতে ট্র্যাক করেছিলাম ।

এটির আমার সমাধানটি হ'ল এটিকে রূপান্তর classকরা struct। প্রায় এটি শুধু একটি শব্দ পরিবর্তন ছিল, ব্যতিক্রম GetHashCodeএবং ToString:

public override string ToString()
{
    return Code ?? string.Empty;
}

public override int GetHashCode()
{
    return Code?.GetHashCode() ?? 0;
}

default(Airport)ব্যবহৃত হয় যেখানে কেস পরিচালনা করতে ।

আমার প্রশ্নগুলো:

  1. কোনও Airportশ্রেণি তৈরি করা বা সাধারণভাবে একটি ভাল সমাধান তৈরি করা ছিল , বা আমি ভুল সমস্যাটি সমাধান করছি / প্রকারটি তৈরি করে এটি ভুল উপায়ে সমাধান করছি? যদি এটি একটি ভাল সমাধান না হয় তবে এর চেয়ে ভাল সমাধান কী?

  2. যেখানে default(Airport)ব্যবহৃত হয় সেখানে আমার অ্যাপ্লিকেশনটির কীভাবে হ্যান্ডেল করা উচিত ? এক ধরণের default(Airport)আমার আবেদনের পক্ষে অযৌক্তিক, তাই আমি এমন if (airport == default(Airport) { throw ... }জায়গাগুলিতে করছিলাম যেখানে Airport(এবং এর Codeসম্পত্তি) উদাহরণ পাওয়া অপারেশনের জন্য গুরুত্বপূর্ণ।

দ্রষ্টব্য: আমি সি # / ভিবি কাঠামো প্রশ্নগুলি পর্যালোচনা করেছি - প্রদত্ত কাঠামোর জন্য অবৈধ বলে বিবেচিত শূন্য ডিফল্ট মানগুলির ক্ষেত্রে কীভাবে এড়ানো যায়? , এবং আমার প্রশ্ন জিজ্ঞাসার আগে স্ট্রাক্ট ব্যবহার করুন বা না করুন , তবে আমি মনে করি যে আমার প্রশ্নগুলি তার নিজের পোস্টের পরোয়ানা দেওয়ার পক্ষে যথেষ্ট আলাদা are


7
আপনার অ্যাপ্লিকেশনটি যেভাবে সম্পাদন করে তাতে আবর্জনা সংগ্রহের কী কোনও উপাদান প্রভাব ফেলে? অন্য কথায়, এটা কি ব্যাপার?
রবার্ট হার্ভে

যাইহোক, হ্যাঁ, শ্রেণি সমাধানটি একটি "ভাল" ছিল। আপনি যেভাবে জানেন তা কোনও নতুন সমস্যা তৈরি না করেই এটি আপনার সমস্যার সমাধান করে।
রবার্ট হার্ভে

2
default(Airport)সমস্যাটি সমাধান করার একটি উপায় হ'ল ডিফল্ট দৃষ্টান্তগুলি কেবল অস্বীকার করে। আপনি প্যারামিটারলেস কনস্ট্রাক্টর লিখে এবং নিক্ষেপ করে InvalidOperationExceptionবা NotImplementedExceptionএটিতে এটি করতে পারেন।
রবার্ট হার্ভে

3
এক পাশের নোটে, আপনার সূচনাটি স্ট্রিংটি আসলে 3 টি আলফা অক্ষর রয়েছে তা নিশ্চিত করার পরিবর্তে, কেন কেবল এটিকে সমস্ত বিমানবন্দর কোডের সীমাবদ্ধ তালিকার সাথে তুলনা করবেন না (যেমন, github.com/datasets/airport-codes বা অনুরূপ)?
ড্যান পিচেলম্যান

2
আমি বেশ কয়েকটি বিয়ার বাজি রাখতে ইচ্ছুক যে এটি কোনও পারফরম্যান্স সমস্যার মূল নয়। একটি সাধারণ ল্যাপটপ 10 এম অবজেক্ট / সেকেন্ডে ক্রমে বরাদ্দ করতে পারে।
এসবেন স্কোভ পেডারসেন

উত্তর:


6

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


আপনি যদি আপনার সিস্টেমে আসা ডেটা নিয়ন্ত্রণ করতে পারেন তবে আপনি আপনার প্রশ্নে পোস্ট করেছেন এমন একটি ক্লাস ব্যবহার করুন। যদি কেউ চালায় তবে default(Airport)তারা একটি nullমান ফিরে পাবে। Equalsনাল বিমানবন্দর অবজেক্টের সাথে তুলনা করার সময় মিথ্যা ফেরত দিতে আপনার ব্যক্তিগত পদ্ধতিটি লিখতে ভুলবেন না , এবং তারপরে NullReferenceExceptionকোডটির অন্য কোথাও উড়তে দিন ।

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

public struct Airport
{
    private string code;

    public Airport(string code)
    {
        // Check `code` for validity, throw exceptions if not valid

        this.code = code;
    }

    public override string ToString()
    {
        return code ?? (code = "---");
    }

    // int GetHashcode()

    // bool Equals(...)

    // bool operator ==(...)

    // bool operator !=(...)

    private bool Equals(Airport other)
    {
        if (other == null)
            // Even if this method is private, guard against null pointers
            return false;

        if (ToString() == "---" || other.ToString() == "---")
            // "Default" values should never match anything, even themselves
            return false;

        // Do a case insensitive comparison to enforce logic that airport
        // codes are not case sensitive
        return string.Equals(
            ToString(),
            other.ToString(),
            StringComparison.InvariantCultureIgnoreCase);
    }
}

এর চেয়ে খারাপ পরিস্থিতি default(Airport)স্ট্রিংয়ে রূপান্তরিত "---"করে অন্য বৈধ বিমানবন্দর কোডের তুলনায় মিথ্যা ফিরিয়ে দেয়। অন্য কোনও ডিফল্ট বিমানবন্দর কোড সহ কোনও "ডিফল্ট" বিমানবন্দর কোড কিছুই মিলছে না।

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

আমি নিয়মগুলি এখানে কিছুটা বাঁকিয়ে দেব, কারণ এটি।


আসল উত্তর (কিছু ত্রুটিযুক্ত ত্রুটি সহ)

আপনি যদি আপনার সিস্টেমে আসা ডেটা নিয়ন্ত্রণ করতে পারেন তবে রবার্ট হার্ভে মন্তব্যে যেমন পরামর্শ দিয়েছিলেন আমি তা করব: প্যারামিটারলেস কনস্ট্রাক্টর তৈরি করুন এবং যখন ডাকা হবে তখন ব্যতিক্রম নিক্ষেপ করুন। এটি সিস্টেমের মাধ্যমে অবৈধ ডেটা প্রবেশ করতে বাধা দেয় default(Airport)

public Airport()
{
    throw new InvalidOperationException("...");
}

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

public Airport()
{
    Code = "---";
}

যেহেতু আপনি stringকোড হিসাবে একটি ব্যবহার করছেন তাই কোনও স্ট্রাক ব্যবহার করার কোনও মানে নেই। কাঠামো স্ট্যাকের উপর বরাদ্দ পেয়েছে, কেবল Codeহিপ মেমরির একটি স্ট্রিংয়ের পয়েন্টার হিসাবে বরাদ্দ করা হয়েছে, সুতরাং এখানে শ্রেণি এবং কাঠামোর মধ্যে কোনও পার্থক্য নেই।

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


যদি আমার অ্যাপ্লিকেশনটি Codeসম্পত্তির জন্য ইন্টার্নযুক্ত স্ট্রিংগুলি ব্যবহার করে , তবে স্ট্রিংয়ের আপনার পয়েন্টটি হিপ মেমোরিতে থাকার বিষয়ে এটি কি আপনার ন্যায্যতা পরিবর্তন করবে?
ম্যাথু

@ ম্যাথিউ: ক্লাস ব্যবহার করা কি আপনাকে পারফরম্যান্সের সমস্যা দিচ্ছে? যদি তা না হয় তবে কোনটি ব্যবহার করবেন তা সিদ্ধান্ত নেওয়ার জন্য একটি মুদ্রা ফ্লিপ করুন।
গ্রেগ বার্গার্ড্ট

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

1
এটি সত্য, এটি সময়ে সময়ে একাডেমিক আলোচনা করাতে আমার আপত্তি নেই যদি এটি আমাকে ভবিষ্যতে আরও ভালভাবে অবহিত সমাধান তৈরি করতে সহায়তা করে।
ম্যাথু

@ ম্যাথিউ: হ্যাঁ, আপনি একেবারে ঠিক বলেছেন। তারা বলে "কথা সুলভ।" কিছু কথা না বলা এবং খারাপ কিছু তৈরি না করার থেকে এটি অবশ্যই সস্তা। :)
গ্রেগ বার্গার্ড্ট

13

ফ্লাইওয়েট প্যাটার্ন ব্যবহার করুন

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

একটি অতিরিক্ত গৌণ সুবিধা (কমপক্ষে জাভাতে, সি # সম্পর্কে নিশ্চিত নয়) হ'ল আপনাকে কোনও equals()পদ্ধতি লেখার দরকার নেই , একটি সাধারণ কাজ ==করবে। একই জন্য hashcode()


3
ফ্লাইওয়েট প্যাটার্নের দুর্দান্ত ব্যবহার।
নীল

2
ধরে নেওয়া যাক ওপি একটি struct এবং না একটি বর্গ ব্যবহার রাখে, তাই না স্ট্রিং interning ইতিমধ্যে পুনর্ব্যবহারযোগ্য স্ট্রিং মান হ্যান্ডলিং? স্ট্রাক্টগুলি ইতিমধ্যে স্ট্যাকের উপরে থাকে, স্ট্রিংগুলি ইতিমধ্যে পুনরায় ব্যবহার করা হয় যাতে মেমরিতে নকল মানগুলি এড়ানো যায়। ফ্লাইওয়েট প্যাটার্ন থেকে আরও কী কী উপকার পাবেন?
ফ্ল্যাটার

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

@ ফ্লাটার যুক্তিসঙ্গত পয়েন্ট। আমি বলবো জুনিয়র প্রোগ্রামারদের স্ট্যাক বনাম হিপ সম্পর্কে যুক্তিযুক্ত করার কম প্রয়োজন। আমার সংযোজনটি দেখুন - সমান () লেখার দরকার নেই।
ব্যবহারকারী949300

1
@ গ্রেগ বার্গার্ড্ট getAirportOrCreate()কোডটি সঠিকভাবে সিঙ্ক্রোনাইজ করা থাকলে রানটাইমের সময় আপনি নতুন বিমানবন্দর তৈরি করতে পারবেন না এমন কোনও প্রযুক্তিগত কারণ নেই reason ব্যবসায়ের কারণ থাকতে পারে।
ব্যবহারকারী949300

3

আমি বিশেষত উন্নত প্রোগ্রামার নই, তবে এটি কি এনুমের জন্য সঠিক ব্যবহার হবে না?

তালিকা বা স্ট্রিং থেকে এনাম ক্লাস তৈরির বিভিন্ন উপায় রয়েছে। এখানে আমি অতীতে যা দেখেছি তা নিশ্চিত না যদিও এটি সবচেয়ে ভাল উপায়।

https://blog.kloud.com.au/2016/06/17/converting-webconfig-values-into-enum-or-list/


2
যখন সম্ভাব্য সহস্র বিভিন্ন মান রয়েছে (যেমন বিমানবন্দর কোডগুলির ক্ষেত্রে), তখন একটি এনাম ব্যবহারিক হয় না।
বেন কট্রেল

হ্যাঁ, তবে আমি যে লিঙ্কটি পোস্ট করেছি তা হ'ল এনমগুল হিসাবে স্ট্রিংগুলি লোড করা যায়। এনাম হিসাবে লুক টেবিলটি লোড করার জন্য এখানে অন্য লিঙ্ক। এটি কিছুটা কাজ হতে পারে তবে এনামগুলির শক্তির সুবিধা নেবে। exceptionnotfound.net/…
অ্যাডাম বি

1
অথবা বৈধ কোডগুলির একটি তালিকা একটি ডাটাবেস বা ফাইল থেকে লোড করা যেতে পারে। তারপরে একটি বিমানবন্দর কোডটি কেবলমাত্র সেই তালিকার মধ্যে থাকতে হবে checked আপনি যখন আর আর মানগুলি এবং / অথবা তালিকাটি পরিচালনা করতে দীর্ঘায়িত হতে চান না তখন আপনি সাধারণত এটি করেন।
নীল

@ বেনকোটারেল যা সঠিকভাবে কোড জেন এবং টি 4 টেমপ্লেটগুলির জন্য।
রাবারডাক

3

আপনি আরও বেশি জিসি ক্রিয়াকলাপ দেখছেন তার একটি কারণ আপনি এখন দ্বিতীয় স্ট্রিং তৈরি করছেন - .ToUpperInvariant()মূল স্ট্রিংয়ের সংস্করণ। কনস্ট্রাক্টর চলার পরে মূল স্ট্রিংটি জিসির জন্য উপযুক্ত এবং দ্বিতীয়টি একই সাথে Airportঅবজেক্টের মতো যোগ্য । আপনি এটি অন্য কোনও ফ্যাশনে ছোট করতে পারবেন (তৃতীয় প্যারামিটারটি এখানে নোট করুন string.Equals()):

public sealed class Airport : IEquatable<Airport>
{
    public Airport(string code)
    {
        if (code == null)
        {
            throw new ArgumentNullException(nameof(code));
        }

        if (code.Length != 3 || !char.IsLetter(code[0])
                             || !char.IsLetter(code[1]) || !char.IsLetter(code[2]))
        {
            throw new ArgumentException(
                "Must be a 3 letter airport code.",
                nameof(code));
        }

        Code = code;
    }

    public string Code { get; }

    public override string ToString()
    {
        return Code; // TODO: Upper-case it here if you really need to for display.
    }

    public bool Equals(Airport other)
    {
        return string.Equals(Code, other?.Code, StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool Equals(object obj)
    {
        return obj is Airport airport && Equals(airport);
    }

    public override int GetHashCode()
    {
        return Code.GetHashCode();
    }

    public static bool operator ==(Airport left, Airport right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Airport left, Airport right)
    {
        return !Equals(left, right);
    }
}

এটি কি সমান (তবে আলাদাভাবে মূলধনযুক্ত) বিমানবন্দরের জন্য বিভিন্ন হ্যাশ কোড দেয় না?
হিরো ওয়ান্ডার্স

হ্যাঁ, আমিও তাই কল্পনা করব। ধূর.
জেসি সি স্লিকার

এটি একটি খুব ভাল পয়েন্ট, এটি কখনই ভাবেনি, আমি এই পরিবর্তনগুলি দেখব।
ম্যাথু

1
সম্পর্কিত GetHashCode, কেবল ব্যবহার করা উচিত StringComparer.OrdinalIgnoreCase.GetHashCode(Code)বা অনুরূপ
ম্যাথু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.