প্রতিবিম্বটি (ওভার) ব্যবহার করা কি খারাপ অভ্যাস?


16

বয়লারপ্লেট কোডের পরিমাণটি যদি হ্রাস করে তবে প্রতিবিম্বটি ব্যবহার করা কি একটি ভাল অনুশীলন?

মূলত পারফরম্যান্স এবং সম্ভবত একপাশে পাঠযোগ্যতা এবং অন্যদিকে অ্যাবস্ট্রাকশন / অটোমেশন / অন্যদিকে বয়লারপ্লেট কোড হ্রাসের মধ্যে একটি বাণিজ্য রয়েছে।

সম্পাদনা: প্রতিবিম্বের প্রস্তাবিত ব্যবহারের উদাহরণ এখানে

একটি উদাহরণ দিতে, অনুমান করা সেখানে একটি বিমূর্ত ক্লাস হয় Baseযা 10 ক্ষেত্রের এবং 3 উপশ্রেণী রয়েছে SubclassA, SubclassBএবং SubclassC10 বিভিন্ন ক্ষেত্রে সঙ্গে প্রতিটি; তারা সব সহজ মটরশুটি হয়। সমস্যাটি হ'ল আপনি দুটি Baseপ্রকারের রেফারেন্স পান এবং আপনি দেখতে চান তাদের সংশ্লিষ্ট বস্তুগুলি একই (উপ) ধরণের এবং সমান কিনা।

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

boolean compare(Base base1, Base, base2) {
    if (base1 instanceof SubclassA && base2 instanceof SubclassA) { 
         SubclassA subclassA1 = (SubclassA) base1;
         SubclassA subclassA2 = (SubclassA) base2;
         compare(subclassA1, subclassA2);
    } else if (base1 instanceof SubclassB && base2 instanceof SubclassB) {
         //the same
    }
    //boilerplate
}

boolean compare(SubclassA subA1, SubclassA subA2) {
    if (!subA1.getField1().equals(subA2.getField1)) {
         return false;
    }
    if (!subA1.getField2().equals(subA2.getField2)) {
         return false;
    }
    //boilerplate
}

boolean compare(SubclassB subB1, SubclassB subB2) {
    //boilerplate
}

//boilerplate

//alternative with reflection 
boolean compare(Base base1, Base base2) {
        if (!base1.getClass().isAssignableFrom(base2.getClass())) {
            System.out.println("not same");
            System.exit(1);
        }
        Method[] methods = base1.getClass().getMethods();
        boolean isOk = true;
        for (Method method : methods) {
            final String methodName = method.getName();
            if (methodName.startsWith("get")) {
                Object object1 = method.invoke(base1);
                Object object2 = method.invoke(base2);
                if(object1 == null || object2 == null)  {
                    continue;
                }
                if (!object1.equals(object2)) {
                    System.out.println("not equals because " + object1 + " not equal with " + object2);
                    isOk = false;
                }
            }
        }

        if (isOk) {
            System.out.println("is OK");
        }
}

20
যে কোনও কিছুর অতিরিক্ত ব্যবহার করা খারাপ অভ্যাস।
তুলাইনস কর্ডোভা

1
@ user61852 ঠিক, অত্যধিক স্বাধীনতা একনায়কতন্ত্রের দিকে পরিচালিত করে। কিছু প্রাচীন গ্রীক ইতিমধ্যে এটি সম্পর্কে জানত।
অট--

6
"খুব বেশি জল আপনার পক্ষে খারাপ হবে। স্পষ্টতই, অত্যধিক পরিমাণে খুব বেশি পরিমাণে হ'ল এটিই এর অর্থ! "- স্টিফেন ফ্রাই
জন পুরী

4
"যে কোনও সময় আপনি নিজেকে ফর্মের কোডটি লেখার সন্ধান করতে পারেন" যদি অবজেক্ট টি 1 টাইপ হয়, তবে কিছু করুন, তবে এটি টি 2 টাইপের হয়, তবে অন্য কিছু করুন, "নিজেকে চড় মারুন
rm5248

উত্তর:


25

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

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

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

এছাড়াও, "বয়লারপ্লেট" কোড, যদি সঠিক শ্রেণিতে রাখা হয় তবে এটি আঁকানো বেশ শক্ত। প্রতিচ্ছবি অতিরিক্ত জটিলতা যুক্ত করে, যার অর্থ বাগের জন্য অতিরিক্ত সম্ভাবনা। উদাহরণস্বরূপ, আপনার পদ্ধতিতে দুটি অবজেক্ট সমান বিবেচিত হবে যদি nullএকটি নির্দিষ্ট ক্ষেত্রের জন্য প্রত্যাবর্তন করে এবং অন্যটি না দেয়। যদি আপনার গেটসগুলির মধ্যে একটি উপযুক্ত ছাড়াই আপনার কোনও বস্তু ফেরত দেয় তবে equals? আপনার if (!object1.equals(object2))ব্যর্থ হবে। এটিকে বাগ প্রবণ করে তোলা এই বিষয়টি হ'ল প্রতিফলন খুব কমই ব্যবহৃত হয়, সুতরাং প্রোগ্রামাররা এর গটছগুলির সাথে তেমন পরিচিত নয়।


12

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

সুতরাং, আপনি বিভিন্ন শ্রেণীর তুলনা করছেন, এটি পদ্ধতি ওভাররাইডের জন্য একটি সঠিক সমস্যা । নোট করুন যে দুটি পৃথক শ্রেণীর উদাহরণ কখনও সমান বিবেচনা করা উচিত নয়। আপনি একই শ্রেণীর উদাহরণ থাকলে কেবলমাত্র সমতার জন্য তুলনা করতে পারেন। কীভাবে সাম্যতার তুলনা সঠিকভাবে প্রয়োগ করা যায় তার একটি উদাহরণের জন্য /programming/27581/overriding-equals-and-hashcode-in-java দেখুন ।


16
+1 - আমাদের মধ্যে কেউ কেউ বিশ্বাস করে যে প্রতিচ্ছবিগুলির যে কোনও ব্যবহারই হ'ল একটি লাল পতাকা যা খারাপ নকশাকে নির্দেশ করে।
রস প্যাটারসন

1
সর্বাধিক সম্ভবত এক্ষেত্রে সমান ভিত্তিক একটি সমাধান আকাঙ্ক্ষিত তবে সাধারণ ধারণা হিসাবে প্রতিফলন সমাধানে কী ভুল? প্রকৃতপক্ষে এটি খুব জেনেরিক এবং সমান পদ্ধতিগুলি প্রতিটি শ্রেণি এবং সাবক্লাসে স্পষ্টভাবে লেখার দরকার নেই (যদিও এগুলি সহজেই একটি ভাল আইডিই দ্বারা উত্পন্ন করা যেতে পারে)।
m3th0dman

2
@ রসপ্যাটারসন কেন?
m3th0dman

2
@ m3th0dman কারন এটি আপনার compare()পদ্ধতির মতো জিনিসগুলির দিকে নিয়ে যায় যে ধরে নিয়ে যে "get" দিয়ে শুরু হওয়া কোনও পদ্ধতিই একজন গেটর এবং তুলনামূলক ক্রিয়াকলাপের অংশ হিসাবে কল করা নিরাপদ এবং উপযুক্ত। এটি অবজেক্টের অভিযুক্ত ইন্টারফেস সংজ্ঞা লঙ্ঘন এবং এটি সমীচীন হতে পারে তবে এটি প্রায় সর্বদা ভুল।
রস প্যাটারসন

4
@ m3th0dman এটি এনক্যাপসুলেশন লঙ্ঘন করে - বেস শ্রেণিকে তার সাবক্লাসে বৈশিষ্ট্য অ্যাক্সেস করতে হবে। তারা বেসরকারী (বা প্রাপ্ত বেসরকারী) হলে কী হবে? বহুবর্ষ সম্পর্কে কী? আমি যদি অন্য সাবক্লাস যুক্ত করার সিদ্ধান্ত নিয়ে থাকি এবং আমি এতে তুলনাটি আলাদাভাবে করতে চাই? ভাল, বেস ক্লাসটি ইতিমধ্যে আমার জন্য এটি করছে এবং আমি এটি পরিবর্তন করতে পারি না। যদি আধ্যাত্মিক কিছু অলস বোঝা হয়? আমি কি তুলনামূলক পদ্ধতিটি করতে চাই? আমি কীভাবে কীভাবে জানতে পারি যে কোনও পদ্ধতিটি দিয়ে শুরু করা হয় getতা কোনও গ্রাহক এবং কোনও কাস্টম পদ্ধতি কিছু ফেরত না?
সুলতান

1

আমার মনে হয় আপনার এখানে দুটি সমস্যা আছে।

  1. স্ট্যাটিক কোড বনাম কত গতিশীল আমার থাকা উচিত?
  2. আমি কীভাবে সাম্যের একটি কাস্টম সংস্করণ প্রকাশ করব?

গতিশীল বনাম স্ট্যাটিক কোড

এটি বহুবর্ষজীবী প্রশ্ন এবং উত্তরটি খুব মতামতযুক্ত।

একদিকে আপনার সংকলক সকল প্রকারের খারাপ কোড ধরতে খুব ভাল। এটি বিশ্লেষণের বিভিন্ন ধরণের মাধ্যমে এটি করে, প্রকার বিশ্লেষণ একটি সাধারণ being এটি জানে যে আপনি Bananaকোডে এমন কোনও বস্তু ব্যবহার করতে পারবেন না যা প্রত্যাশা করে Cog। এটি আপনাকে সংকলনের ত্রুটির মাধ্যমে জানায়।

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

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

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

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

কাস্টম সমতা

আমি যখন বুঝতে পারি যে equalsসাধারণত দুটি বস্তুর তুলনামূলকভাবে প্রদত্ত প্রসঙ্গে উপযুক্ত না হয় তার জন্য জাভা প্রচলিত পদ্ধতিতে নির্ভর করে।

অন্য উপায় আছে, এবং এটি একটি জাভা মান। একে একে তুলনাকারী বলা হয় ।

আপনি কীভাবে আপনার তুলনাকারী বাস্তবায়ন করেন তা নির্ভর করে আপনি কী তুলনা করছেন এবং কীভাবে।

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

1

আমি যতটা সম্ভব প্রতিফলিত প্রোগ্রামিং এড়াতে পছন্দ করি কারণ এটি

  • সংকলক দ্বারা স্থিতিশীলভাবে চেক করতে কোডটিকে আরও শক্ত করে তোলে
  • কোডটি যুক্তিযুক্ত করে তোলে
  • কোডটিকে চুল্লি থেকে শক্ত করে তোলে

এটি সাধারণ পদ্ধতি কলগুলির চেয়েও অনেক কম পারফরম্যান্ট; এটি প্রস্থ বা আরও বেশি ক্রমের সাহায্যে ধীর হয়ে উঠত।

স্ট্যাটিকালি কোড চেক করা হচ্ছে

যে কোনও প্রতিচ্ছবিযুক্ত কোড স্ট্রিং ব্যবহার করে ক্লাস এবং পদ্ধতিগুলি সন্ধান করে; মূল উদাহরণে এটি "get" দিয়ে শুরু হওয়া কোনও পদ্ধতির সন্ধান করছে; এটি "গেটটিসবার্গ অ্যাড্রেস ()" এর মতো গিটারগুলি ছাড়াও অন্যান্য পদ্ধতিগুলি ফিরিয়ে দেবে। কোডগুলিতে নিয়মগুলি আরও কড়া করা যেতে পারে তবে পয়েন্টটি রয়ে গেছে যে এটি রানটাইম চেক ; একটি আইডিই এবং সংকলক সাহায্য করতে পারে না। সাধারণভাবে আমি "স্ট্র্যারি টাইপড" বা "আদিম উন্মাদিত" কোডটি অপছন্দ করি।

সম্পর্কে শক্ত কারণ

রিফ্লেকটিভ কোডটি সহজ পদ্ধতি কলগুলির চেয়ে বেশি ভার্বোজ। আরও কোড = আরও বাগ, বা বাগের জন্য কমপক্ষে আরও বেশি সম্ভাবনা, আরও কোড পড়ার, পরীক্ষা করার জন্য ইত্যাদি Less কম বেশি is

হার্ড টু রিফ্যাক্টর

কারণ কোডটি আস্তে আস্তে / গতিশীল ভিত্তিক; প্রতিচ্ছবি দৃশ্যের সাথে সাথেই আপনি আইডিইর রিফ্যাক্টরিং সরঞ্জামগুলি ব্যবহার করে 100% আত্মবিশ্বাসের সাথে কোড রিফ্যাক্টর করতে পারবেন না কারণ আইডিই প্রতিচ্ছবি ব্যবহার করতে পারে না।

মূলত, যদি সম্ভব হয় তবে সাধারণ কোডে প্রতিবিম্ব এড়ান; একটি উন্নত নকশা জন্য সন্ধান করুন।


0

সংজ্ঞা অনুসারে কোন কিছুর অতিরিক্ত ব্যবহার খারাপ, তাইনা? সুতরাং আপাতত (ওভার) থেকে মুক্তি পাওয়া যাক।

আপনি কি বসন্তের আশ্চর্যরকম ভারী অভ্যন্তরীণ প্রতিচ্ছবি ব্যবহারকে খারাপ অভ্যাস বলবেন?

টীকাগুলি ব্যবহার করে বসন্তের প্রতিচ্ছবি প্রতিবিম্বিত হয় - তাই হাইবারনেট (এবং সম্ভবত কয়েক ডজন / শত অন্যান্য সরঞ্জাম)।

আপনি যদি এটি নিজের কোডে ব্যবহার করেন তবে সেই নিদর্শনগুলি অনুসরণ করুন। আপনার ব্যবহারকারীর আইডিই এখনও তাদের সহায়তা করতে পারে তা নিশ্চিত করতে টীকাগুলি ব্যবহার করুন (আপনি যদি আপনার কোডের একমাত্র "ব্যবহারকারী" হন, তবে প্রতিবিম্বের অযত্ন ব্যবহার সম্ভবত আপনাকে বাটটিতে কাটাতে ফিরে আসবে)।

তবে কীভাবে আপনার কোডটি বিকাশকারীরা ব্যবহার করবেন এমনকি প্রতিবিম্বের সহজতম ব্যবহার সম্ভবত অতিরিক্ত ব্যবহার।


0

আমি মনে করি এই উত্তরগুলির বেশিরভাগটি পয়েন্টটি মিস করে।

  1. হ্যাঁ, আপনার সম্ভবত লেখা উচিত equals()এবং hashcode()যেমনটি @ কার্লবিলিফেল্ট লিখেছেন।

  2. তবে, অনেকগুলি ক্ষেত্র সহ একটি শ্রেণীর জন্য, এটি ক্লান্তিকর বয়লারপ্লেট হতে পারে।

  3. সুতরাং, এটি নির্ভর করে

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

    • ক্ষেত্রগুলিকে একটি মানচিত্রে স্থাপন করা।
    • আপনি এখনও কাস্টম getters এবং সেটটার লিখতে পারেন
    • Map.equals()আপনার তুলনা জন্য ব্যবহার করুন। (বা Map.hashcode())

উদাহরণস্বরূপ ( দ্রষ্টব্য : নাল চেকগুলি উপেক্ষা করে স্ট্রিং কীগুলির পরিবর্তে সম্ভবত এনাম ব্যবহার করা উচিত, যা বেশি দেখানো হয়নি ...)

class TooManyFields {
  private HashMap<String, Object> map = new HashMap<String, Object>();

  public setFoo(int i) { map.put("Foo", Integer.valueOf(i)); }
  public int getFoo()  { return map.get("Foo").intValue(); }

  public setBar(Sttring s) { map.put("Bar", s); }
  public String getBar()  { return map.get("Bar").toString(); }

  ... more getters and setters ...

  public boolean equals(Object o) {
    return (o instanceof TooManyFields) &&
           this.map.equals( ((TooManyFields)o).map);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.