জাভা নাম লুকানো: হার্ড ওয়ে


96

নাম গোপনে আমার একটি সমস্যা রয়েছে যা সমাধান করা অত্যন্ত কঠিন। এখানে একটি সরলীকৃত সংস্করণ যা সমস্যাটি ব্যাখ্যা করে:

একটি শ্রেণি আছে: org.A

package org;
public class A{
     public class X{...}
     ...
     protected int net;
}

তারপরে একটা ক্লাস আছে net.foo.X

package net.foo;
public class X{
     public static void doSomething();
}

এবং এখন, এখানে সমস্যাযুক্ত শ্রেণি যা উত্তরাধিকার সূত্রে প্রাপ্ত Aএবং কল করতে চায়net.foo.X.doSomething()

package com.bar;
class B extends A {

    public void doSomething(){
        net.foo.X.doSomething(); // doesn't work; package net is hidden by inherited field
        X.doSomething(); // doesn't work; type net.foo.X is hidden by inherited X
    }
}

যেমন আপনি দেখতে পাচ্ছেন, এটি সম্ভব নয়। আমি সাধারণ নামটি ব্যবহার করতে পারি না Xকারণ এটি উত্তরাধিকার সূত্রে প্রাপ্ত গোপন। আমি পুরোপুরি যোগ্য নামটি ব্যবহার করতে পারি না net.foo.X, কারণ netউত্তরাধিকারসূত্রে প্রাপ্ত ক্ষেত্রের দ্বারা গোপন।

ক্লাসটি Bআমার কোড বেসে রয়েছে; ক্লাস net.foo.Xএবং org.Aলাইব্রেরি ক্লাস হয়, তাই আমি তাদের পরিবর্তন করতে পারবেন না!

আমার একমাত্র সমাধানটি এর মতো দেখাচ্ছে: আমি অন্য ক্লাসকে কল করতে পারি যা ঘুরে ফিরে কল করে X.doSomething(); তবে এই শ্রেণিটি কেবল নাম সংঘর্ষের কারণে উপস্থিত থাকবে যা খুব অগোছালো বলে মনে হচ্ছে! সেখানে কোন সমাধান যা আমি সরাসরি কল করতে পারেন X.doSomething()থেকেB.doSomething() ?

এমন একটি ভাষায় যা গ্লোবাল নেমস্পেস নির্দিষ্ট করতে দেয়, উদাহরণস্বরূপ, global::সি # বা ::সি ++ এ, আমি কেবল netএই গ্লোবাল উপসর্গের সাথে উপসর্গ করতে পারি , তবে জাভা সেটি অনুমতি দেয় না।


কিছু কুইকফিক্স এটি হতে পারে: public void help(net.foo.X x) { x.doSomething(); }এবং সাথে কল করুনhelp(null);
অ্যাবসার্ড-মাইন্ড

@ অ্যাবসার্ড-মাইন্ড: ঠিক আছে, অস্তিত্বহীন কোন অবজেক্টের মাধ্যমে স্থিতিশীল পদ্ধতি কল করা আমার সমাধানের চেয়ে আরও মজাদার মনে হচ্ছে :)। এমনকি আমি একটি সংকলক সতর্কতাও গ্রহণ করব। তবে সত্য, এটি খনি ছাড়াও অন্য একটি সমাধান হবে।
জিক্সিকাইড

@ জেমসবি: এটি ভুল এক্সকে সংশোধন করবে! net.foo.Xপদ্ধতি আছে, না org.A.X!
জেলিক্সাইড

4
আপনি কি উত্তরাধিকারী হতে হবে A? উত্তরাধিকার এতটা বাজে হতে পারে, যেমন আপনি পেয়েছেন…
ডোনাল ফেলো

4
I could call another class that in turn calls X.doSomething(); but this class would only exist because of the name clash, which seems very messyপরিষ্কার কোডের মনোভাবের জন্য +1 তবে আমার কাছে মনে হচ্ছে এটি এমন একটি পরিস্থিতি যা আপনার একটি ট্রেড অফ করা উচিত। কেবল এটি করুন, এবং আপনাকে কেন এটি করতে হয়েছিল (সম্ভবত এই প্রশ্নের লিঙ্ক সহ) সম্পর্কে একটি দীর্ঘ দীর্ঘ মন্তব্য দিন।
সাম্পাথিস্রিস

উত্তর:


84

আপনি টাইপটিতে একটি কাস্ট করতে পারেন nullএবং তারপরে সেই পদ্ধতিতে অনুরোধ করতে পারেন (যা কাজ করবে, যেহেতু লক্ষ্য বস্তু স্থির পদ্ধতিগুলির অনুরোধের সাথে জড়িত নয়)।

((net.foo.X) null).doSomething();

এর সুবিধা রয়েছে

  • পার্শ্ব প্রতিক্রিয়া মুক্ত হওয়া (তাত্ক্ষণিক সমস্যা) net.foo.X ),
  • কোনও কিছুর নতুন নামকরণের প্রয়োজন নেই (যাতে আপনি Bযে নামটি চান তা আপনার কাছে পদ্ধতিটি দিতে পারেন; সে কারণেই এimport static আপনার সঠিক ক্ষেত্রে কোনও কাজ হবে না),
  • প্রতিনিধি শ্রেণির প্রবর্তনের প্রয়োজন নেই (যদিও এটি একটি ভাল ধারণা হতে পারে ...), এবং
  • ওভারহেড বা প্রতিবিম্ব API এর সাথে কাজ করার জটিলতার প্রয়োজন নেই।

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

@SuppressWarnings("static-access")

একটি উপযুক্ত (ন্যূনতম!) এনকোলেজিং পয়েন্টে সংকলকটি বন্ধ হয়ে যাবে।


4
কেন না? আপনি কেবল সঠিক কাজটি করবেন এবং কোডটি রিফ্যাক্টর করলেন।
গিম্বি

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

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

4
সৃজনশীলতার পক্ষে ভোট দিন, যদিও আমি প্রডাকশন কোডে কখনও এটি করব না। আমি বিশ্বাস করি যে ইন্ডিরিয়েশনই এই সমস্যার উত্তর (এটি কি সব সমস্যার জন্য নয়?)
ইথানফার

এই সমাধানের জন্য ডোনালকে ধন্যবাদ। আসলে, এই সমাধানটি সেই জায়গাগুলিকে হাইলাইট করে যেখানে "টাইপ" ব্যবহার করা যেতে পারে এবং একটি ভেরিয়েবল ব্যবহার করা যায় না। সুতরাং, একটি "castালাই" -এ, একই নামের সাথে কোনও ভেরিয়েবল থাকলেও সংকলক "প্রকার" চয়ন করবে। এরকম আরও আকর্ষণীয় মামলার জন্য আমি 2 "জাভা পিটফলস" বইয়ের সুপারিশ করব: Books.google.co.in/books/about/… বই. google.co.in.in / বই / অ্যাবআউট /
আরআরএম

38

সম্ভবত এটি পরিচালনা করার সবচেয়ে সহজ (প্রয়োজনীয়ভাবে সহজতম নয়) উপায়টি কোনও প্রতিনিধি শ্রেণীর সাথে থাকবে:

import net.foo.X;
class C {
    static void doSomething() {
         X.doSomething();
    }
}

এবং তারপর ...

class B extends A {
    void doX(){
        C.doSomething();
    }
}

এটি কিছুটা ভার্জোজ, তবে খুব নমনীয় - আপনি যেভাবে চান তার আচরণ করতে এটি পেতে পারেন; এছাড়াও এটি staticপদ্ধতি এবং ইনস্ট্যান্টিয়েটেড অবজেক্ট উভয় ক্ষেত্রে একইভাবে কাজ করে works

প্রতিনিধি অবজেক্ট সম্পর্কে আরও এখানে: http://en.wikedia.org/wiki/Delegation_ Pattern


সম্ভবত সবচেয়ে পরিষ্কার সমাধান সরবরাহ করা হয়েছে। আমার যদি সমস্যা হয় তবে আমি সম্ভবত এটি ব্যবহার করব।
লর্ডঅফ দ্য পিগস

37

আপনি একটি স্থিতিশীল আমদানি ব্যবহার করতে পারেন:

import static net.foo.X.doSomething;

class B extends A {
    void doX(){
        doSomething();
    }
}

এটি দেখুন Bএবং Aনামকরণ পদ্ধতি নেইdoSomething


নেট.ফু.এক্স.ডো.সোমিংয়ের কি কেবল প্যাকেজ অ্যাক্সেস নেই? মানে আপনি এটি প্যাকেজ com.bar থেকে অ্যাক্সেস করতে পারবেন না
জেমসবি

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

4
তবে আসল প্রশ্নটি সক্রিয়ভাবে doSomethingপদ্ধতিটির নাম হিসাবে সক্রিয়ভাবে ব্যবহার করতে চাইছে বলে মনে হচ্ছে B...
ডোনাল ফেলো

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

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

16

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

জাভা: নতুন ক্লাসের ইনস্ট্যান্স যেখানে কোনও ডিফল্ট কনস্ট্রাক্টর নেই

এবং তারপরে এই পদ্ধতিটি অনুরোধ করুন।

অথবা, কেবল প্রতিবিম্বের সাথে পদ্ধতিটি নিজেই প্রার্থনা করুন: প্রতিবিম্বটি ব্যবহার করে একটি স্ট্যাটিক পদ্ধতি শুরু করা

Class<?> clazz = Class.forName("net.foo.X");
Method method = clazz.getMethod("doSomething");
Object o = method.invoke(null);

অবশ্যই, এগুলি অবশ্যই শেষ রিসর্ট।


4
এই উত্তর এখন অবধি সবচেয়ে বড় ওভারকিল - থাম্বস আপ :)
জ্যাকিসাইডাইড

4
এই উত্তরের জন্য আপনার একটি সমাপ্তি ব্যাজ পাওয়া উচিত; আপনি সেই একক দরিদ্র ব্যক্তির জন্য উত্তর সরবরাহ করেছেন যাকে জাভা প্রাচীন সংস্করণ ব্যবহার করতে হবে এবং এই সঠিক সমস্যার সমাধান করতে হবে।
গিম্বি

static importবৈশিষ্ট্যটি কেবলমাত্র যুক্ত করা হয়েছিল বলে আমি আসলে ভাবিনি Java 1.5। আমি 1.4 বা তার জন্য নীচে বিকাশ হওয়া লোকদের হিংসা করি না, আমাকে একবার করতে হয়েছিল এবং এটি ভয়ানক ছিল!
এপিকপান্ডা ফোরস

4
@ জিম্বি: ঠিক আছে, এখনও ((net.foo.X)null).doSomething()সমাধান রয়েছে যা পুরানো জাভাতে কাজ করে। কিন্তু যদি টাইপ Aএমনকি একটি ভেতরের প্রকার net, তাহলে এই শুধুমাত্র উত্তর যে অবশেষ বৈধ :) হয়।
জেক্সিকাইড

6

সত্যই উত্তর নয় তবে আপনি এক্স এর একটি উদাহরণ তৈরি করতে এবং এতে স্থির পদ্ধতিটি কল করতে পারেন। আপনার পদ্ধতিটি কল করার জন্য এটি কোনও উপায় (নোংরা আমি স্বীকার করি)।

(new net.foo.X()).doSomething();

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

@gexicide কাস্টিংয়ের এই ধারণাটি এটির nullঅন্যতম পরিষ্কার উপায় বলে মনে হয়। একটি প্রয়োজন @SuppressWarnings("static-access")সতর্কবার্তা-মুক্ত হতে ...
Donal ফেলোগণ

সম্পর্কে নির্ভুলতার জন্য ধন্যবাদ null, তবে nullingালাই আমার কাছে সর্বদা হার্ট ব্রেকার হয়ে থাকে।
মাইকেল লাফারগ

4

কোনও castালাই করার বা কোনও অদ্ভুত সতর্কবাণী দমন করার বা কোনও বাড়াবাড়ি উদাহরণ তৈরি করার দরকার নেই। আপনি কেবল সাব-ক্লাসের মাধ্যমে প্যারেন্ট ক্লাসের স্ট্যাটিক পদ্ধতিতে কল করতে পারেন তা ব্যবহার করে একটি কৌশল। ( এখানে আমার হ্যাকিশ সমাধানের মতো ।)

এই জাতীয় একটি ক্লাস তৈরি করুন

public final class XX extends X {
    private XX(){
    }
}

(এই চূড়ান্ত শ্রেণীর ব্যক্তিগত নির্মাতা নিশ্চিত করে যে কেউ দুর্ঘটনাক্রমে এই শ্রেণীর উদাহরণ তৈরি করতে পারে না))

তারপরে আপনি এর X.doSomething()মাধ্যমে কল করতে পারেন:

    public class B extends A {

        public void doSomething() {
            XX.doSomething();
        }

আকর্ষণীয়, অন্য একটি পদ্ধতি। তবে স্থির পদ্ধতি সহ শ্রেণিটি একটি চূড়ান্ত ইউটিলিটি শ্রেণি।
জেক্সিকাইড

হ্যাঁ, এই কৌশলটি এই ক্ষেত্রে ব্যবহার করতে পারবেন না। স্থির পদ্ধতিটি একটি ভাষা কেন ব্যর্থ এবং স্কালার অবজেক্টের পন্থা গ্রহণ করা উচিত তার অন্য একটি কারণ।
বিলক.সিএন

যদি আপনি যাইহোক অন্য শ্রেণি তৈরি করতে চলেছেন, তবে ব্লগটিটি উত্তরে বর্ণিত ডেলিগেট ক্লাস ব্যবহার করা সম্ভবত সেরা।
লর্ডঅফ দ্য পিগস

@LordOfThePigs এটি যদিও অতিরিক্ত পদ্ধতি কল এবং ভবিষ্যতের রিফ্যাক্টরিং বোঝা এড়িয়ে চলে। নতুন শ্রেণিটি মূলত একটি উপাধি হিসাবে কাজ করে।
বিলক.cn

2

আপনি যদি গোলবালনস্পেসটি দেওয়ার চেষ্টা করেন তবে সমস্ত ফাইল একই ফোল্ডারে রয়েছে। ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )

    package com.bar;
      class B extends A {

       public void doSomething(){
         com.bar.getGlobal().net.foo.X.doSomething(); // drill down from the top...

         }
     }

কিভাবে কাজ করে? আফাইক getGlobal()প্যাকেজগুলির জন্য একটি জাভা পদ্ধতি নয় ... (আমি মনে করি জাভাতে প্যাকেজগুলির কোনও পদ্ধতি থাকতে পারে না ...)
সিইজি

1

উত্তরাধিকারের তুলনায় রচনাটি পছন্দনীয় এই কারণগুলির মধ্যে একটি।

package com.bar;
import java.util.concurrent.Callable;
public class C implements Callable<org.A>
{
    private class B extends org.A{
    public void doSomething(){
        C.this.doSomething();
    }
    }

    private void doSomething(){
    net.foo.X.doSomething();
    }

    public org.A call(){
    return new B();
    }
}

0

আমি কৌশল প্যাটার্ন ব্যবহার করব।

public interface SomethingStrategy {

   void doSomething();
}

public class XSomethingStrategy implements SomethingStrategy {

    import net.foo.X;

    @Override
    void doSomething(){
        X.doSomething();
    }
}

class B extends A {

    private final SomethingStrategy strategy;

    public B(final SomethingStrategy strategy){
       this.strategy = strategy;
    }

    public void doSomething(){

        strategy.doSomething();
    }
}

এখন আপনি নিজের নির্ভরতাও ডিউপল করেছেন, সুতরাং আপনার ইউনিট পরীক্ষাগুলি লিখতে আরও সহজ হবে।


আপনি একটি যোগ করার জন্য ভুলে গিয়ে থাকেন implements SomethingStrategyউপর XSomethingStrategyবর্গ ঘোষণা।
রিকার্ডো সুজা

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