কোনও স্ট্রিং ধ্রুবককে কেবলমাত্র একবার ব্যবহার করা হলে তা সংজ্ঞায়িত করা উচিত?


24

আমরা জ্যাক্সেনের জন্য একটি অ্যাডাপ্টার (জাভার জন্য একটি এক্সপথ গ্রন্থাগার) বাস্তবায়ন করছি যা আমাদের অ্যাপ্লিকেশনটির ডেটা মডেল অ্যাক্সেস করতে এক্সপথ ব্যবহার করতে দেয়।

ক্লাসগুলি মানচিত্রের স্ট্রিংগুলি (জ্যাক্সেন থেকে আমাদের কাছে প্রেরণ করা হয়েছে) আমাদের ডেটা মডেলের উপাদানগুলিতে প্রয়োগ করে এটি করা হয়। আমরা অনুমান করি যে আমাদের মোট 1000 টিরও বেশি স্ট্রিং তুলনা সহ প্রায় 100 টি ক্লাসের প্রয়োজন হবে।

আমি মনে করি যে এটি করার সর্বোত্তম উপায়টি যদি সহজভাবে / অন্যথায় প্রতিটি স্ট্রিংকে ধ্রুবক হিসাবে সংজ্ঞায়িত না করে কোডে সরাসরি স্ট্রিং দিয়ে লেখা থাকে। উদাহরণ স্বরূপ:

public Object getNode(String name) {
    if ("name".equals(name)) {
        return contact.getFullName();
    } else if ("title".equals(name)) {
        return contact.getTitle();
    } else if ("first_name".equals(name)) {
        return contact.getFirstName();
    } else if ("last_name".equals(name)) {
        return contact.getLastName();
    ...

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

private static final String NAME = "name";
private static final String TITLE = "title";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";

public Object getNode(String name) {
    if (NAME.equals(name)) {
        return contact.getFullName();
    } else if (TITLE.equals(name)) {
        return contact.getTitle();
    } else if (FIRST_NAME.equals(name)) {
        return contact.getFirstName();
    } else if (LAST_NAME.equals(name)) {
        return contact.getLastName();
    ...

এই ক্ষেত্রে আমি এটি একটি খারাপ ধারণা বলে মনে করি। ধ্রুবকটি কেবল একবারে getNode()পদ্ধতিতে ব্যবহৃত হবে । স্ট্রিংগুলি সরাসরি ব্যবহার করা ধ্রুবকগুলি ব্যবহার করার মতো পড়া এবং বুঝতে পারা সহজ, এবং আমাদের কমপক্ষে এক হাজার লাইনের কোড লেখা বাঁচায়।

সুতরাং একক ব্যবহারের জন্য স্ট্রিং ধ্রুবককে সংজ্ঞায়িত করার কোনও কারণ আছে? না সরাসরি স্ট্রিং ব্যবহার করা গ্রহণযোগ্য?


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


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

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

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


3
আপনি যদি বিবৃতিগুলি করেন তবে 1000 টি ম্যানুয়ালি কীবোর্ড করার পরিকল্পনা নেই?
জেফো

1
আমি খুব দুঃখ পেয়েছি যে কিছু সাধারণ ভাষায় এই সাধারণ কিছুটি কতটা অপ্রীতিকর হতে পারে ...
জোন পূর্ডি

5
জাভা 7 স্ট্রিংকে switchলেবেল হিসাবে অনুমতি দেয় । ifক্যাসকেডের পরিবর্তে একটি সুইচ ব্যবহার করুন ।
মনিকা পুনরায় ইনস্টল করুন - এম। শ্রাইডার

3
আপনি যদি কোনও স্ট্রিংকে তার এনাম ভ্যালুতে রূপান্তর করেন তবে এনাম রূপান্তরটি 15 গুণ ধীর হয়! সরাসরি এনাম পাস করুন এবং একই ধরণের অন্য এনাম মানের সাথে তুলনা করুন!
নীল

2
হ্যাশম্যাপের মতো গন্ধ একটি সমাধান হতে পারে।
মারিওডিএস 18

উত্তর:


5

এটা চেষ্টা কর. প্রাথমিক প্রতিচ্ছবি অবশ্যই ব্যয়বহুল, তবে আপনি যদি এটি বহুবার ব্যবহার করতে যাচ্ছেন যা আমি মনে করি আপনি যা করবেন তবে এটি আপনি যা প্রস্তাব দিচ্ছেন এটি অবশ্যই একটি ভাল সমাধান। আমি প্রতিবিম্ব ব্যবহার করা পছন্দ করি না, তবে আমি প্রতিবিম্বের বিকল্পটি পছন্দ না করলে নিজেকে এটি ব্যবহার করতে দেখি। আমি মনে করি এটি আপনার দলকে অনেক মাথাব্যথা বাঁচাতে পারে, তবে আপনাকে অবশ্যই পদ্ধতির নামটি (ছোট হাতের অক্ষরে) পাস করতে হবে।

অন্য কথায়, "নাম" পাস করার পরিবর্তে, আপনি "পুরো নাম" পাস করতেন কারণ গেট পদ্ধতির নাম "getFullName ()" হয়।

Map<String, Method> methodMapping = null;

public Object getNode(String name) {
    Map<String, Method> methods = getMethodMapping(contact.getClass());
    return methods.get(name).invoke(contact);
}

public Map<String, Method> getMethodMapping(Class<?> contact) {
    if(methodMapping == null) {
        Map<String, Method> mapping = new HashMap<String, Method>();
        Method[] methods = contact.getDeclaredMethods();
        for(Method method : methods) {
            if(method.getParameterTypes().length() == 0) {
                if(method.getName().startsWith("get")) {
                    mapping.put(method.getName().substring(3).toLower(), method);
                } else if (method.getName().startsWith("is"))) {
                    mapping.put(method.getName().substring(2).toLower(), method);
                }
            }
        }
        methodMapping = mapping;
    }
    return methodMapping;
}

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

public class ContactWrapper {
    private Contact contact;

    public ContactWrapper(Contact contact) {
        this.contact = contact;
    }

    public String getFullName() {
        return contact.getFullName();
    }
    ...
}

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


আমি পদ্ধতিগুলির মাধ্যমে একটি মোড়কের বস্তুর ধারণা পছন্দ করি .invoke()কারণ এটি স্ট্রিং ধ্রুবকগুলি সম্পূর্ণভাবে সরিয়ে দেয়। আমি মানচিত্রটি সেট আপ করার জন্য রানটাইম প্রতিবিম্বের বিষয়ে এতটা আগ্রহী নই, যদিও getMethodMapping()কোনও staticব্লকের মধ্যে সম্পাদন করা ঠিক হবে যাতে সিস্টেমটি একবার চালু হওয়ার পরিবর্তে এটি স্টার্টআপে ঘটে।
গুচ

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

@ নীল কেন অ্যাপাচি কমন্স থেকে বিয়ান ইউটিস ব্যবহার করবেন না? এটি এম্বেড করা অবজেক্টগুলিকে সমর্থন করে। আপনি একটি সম্পূর্ণ ডেটা স্ট্রাকচারের মধ্য দিয়ে যেতে পারেনজেজ.এটিআরএ.এটিটিবি.এটিআরএন এবং এতে আরও অনেকগুলি সম্ভাব্য রয়েছে :-)
লাইভ

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

5

যদি সম্ভব হয় তবে জাভা 7 ব্যবহার করুন যা আপনাকে switchবিবৃতিতে স্ট্রিং ব্যবহার করতে দেয় ।

Http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html থেকে

public class StringSwitchDemo {

    public static int getMonthNumber(String month) {

        int monthNumber = 0;

        if (month == null) {
            return monthNumber;
        }

        switch (month.toLowerCase()) {
            case "january":
                monthNumber = 1;
                break;
            case "february":
                monthNumber = 2;
                break;
            case "march":
                monthNumber = 3;
                break;
            case "april":
                monthNumber = 4;
                break;
            case "may":
                monthNumber = 5;
                break;
            case "june":
                monthNumber = 6;
                break;
            case "july":
                monthNumber = 7;
                break;
            case "august":
                monthNumber = 8;
                break;
            case "september":
                monthNumber = 9;
                break;
            case "october":
                monthNumber = 10;
                break;
            case "november":
                monthNumber = 11;
                break;
            case "december":
                monthNumber = 12;
                break;
            default: 
                monthNumber = 0;
                break;
        }

        return monthNumber;
    }

    public static void main(String[] args) {

        String month = "August";

        int returnedMonthNumber =
            StringSwitchDemo.getMonthNumber(month);

        if (returnedMonthNumber == 0) {
            System.out.println("Invalid month");
        } else {
            System.out.println(returnedMonthNumber);
        }
    }
}

আমি পরিমাপ করি নি, তবে আমি বিশ্বাস করি যে স্যুইচ বিবৃতিগুলি তুলনার দীর্ঘ তালিকার পরিবর্তে একটি জাম্প টেবিলের সাথে সংকলন করে। এটি আরও দ্রুত হওয়া উচিত।

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


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

একটি খুব ভাল পয়েন্ট; এটি যদি ভাল অভিনয় করে তবে এটি কেবল জাভা 7 এ যাওয়ার জন্য উপযুক্ত হতে পারে ...
গ্যাচ

4

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


আমরা বিদ্যমান পদ্ধতিগুলি টীকা দেওয়ার বিষয়টি বিবেচনা করেছি, তবে কিছু ম্যাপিং একাধিক অবজেক্টকে (উদাহরণস্বরূপ "দেশ" ম্যাপিং object.getAddress().getCountry()) অতিক্রম করে যা টীকাগুলির সাথে প্রতিনিধিত্ব করা কঠিন। যদি / অন্য স্ট্রিংয়ের তুলনাগুলি সুন্দর না হয় তবে তারা দ্রুত, নমনীয়, বোঝা সহজ এবং ইউনিট পরীক্ষায় সহজ।
গাচ

1
আপনি টাইপস এবং ত্রুটির সম্ভাবনা সম্পর্কে ঠিক বলেছেন; আমার একমাত্র প্রতিরক্ষা ইউনিট পরীক্ষা আছে। অবশ্যই এর অর্থ আরও কোড ...
গ্যাচ

2

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


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

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

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

তবে আপনি যখন বিবৃতিটি পড়ছেন, আপনাকে ফিরে যেতে হবে এবং পরীক্ষা করতে হবে যে ধ্রুবকটিতে আপনার মনে হয় যে স্ট্রিংটি রয়েছে - এখানে কোনও কিছুই সংরক্ষণ করা হয়নি।
জেমস অ্যান্ডারসন

1
সম্ভবত, তবে এই কারণেই আমি আমার ধ্রুবকের নামটি ভাল রাখি।
বার্নার্ড

1

যদি আপনার নামকরণ সামঞ্জস্যপূর্ণ হয় (ওরফে "some_whatever"সর্বদা এতে ম্যাপ করা থাকে getSomeWhatever()) তবে আপনি get পদ্ধতিটি নির্ধারণ এবং সম্পাদন করতে প্রতিবিম্বটি ব্যবহার করতে পারেন।


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

0

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

public Object getNode(String name) {
    return SomeModelClassHelper.getNode(this, name);
}

ক্লাস প্রতি একবার সমস্যা হওয়া উচিত নয়। বিকল্পভাবে, আপনি যেমন কিছু লিখতে পারে

public Object getNode(String name) {
    return getHelper(getClass()).getNode(this, name);
}

একটি সাধারণ সুপারক্লাসে।


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


আমি প্রতিচ্ছবি সরাসরি ব্যবহার বিবেচনা করব। অবশ্যই, প্রতিবিম্বটি ধীর, তবে এটি কেন ধীর? এটি কারণ আপনাকে যা করতে হবে তা সমস্ত কাজ করতে হয়, যেমন, ক্ষেত্রের নামটি স্যুইচ করুন।

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