मैं एक पैकेज में एक जावा वर्ग लिखने में सक्षम होना चाहता हूं जो किसी अन्य पैकेज में एक वर्ग के गैर-सार्वजनिक तरीकों को एक्सेस कर सकता है, बिना इसे दूसरे वर्ग का उपवर्ग बनाए बिना। क्या यह संभव है?
मैं एक पैकेज में एक जावा वर्ग लिखने में सक्षम होना चाहता हूं जो किसी अन्य पैकेज में एक वर्ग के गैर-सार्वजनिक तरीकों को एक्सेस कर सकता है, बिना इसे दूसरे वर्ग का उपवर्ग बनाए बिना। क्या यह संभव है?
जवाबों:
यहाँ एक छोटी सी तरकीब है जिसका उपयोग मैं JAVA में C ++ मित्र तंत्र को दोहराने के लिए करता हूँ।
कहते हैं कि मेरे पास एक क्लास Romeo
और दूसरी क्लास है Juliet
। वे नफरत के कारणों के लिए अलग-अलग पैकेज (परिवार) में हैं।
Romeo
चाहता है cuddle
Juliet
और Juliet
केवल Romeo
cuddle
उसे जाने देना चाहता है ।
C ++ में, एक (प्रेमी) के रूप में Juliet
घोषित Romeo
किया जाएगा , friend
लेकिन जावा में ऐसी चीजें नहीं हैं।
यहाँ कक्षाएं और चाल हैं:
महिलायें पहले :
package capulet;
import montague.Romeo;
public class Juliet {
public static void cuddle(Romeo.Love love) {
Objects.requireNonNull(love);
System.out.println("O Romeo, Romeo, wherefore art thou Romeo?");
}
}
तो विधि Juliet.cuddle
है, public
लेकिन आपको Romeo.Love
इसे कॉल करने की आवश्यकता है । यह Romeo.Love
"हस्ताक्षर सुरक्षा" के रूप में इसका उपयोग यह सुनिश्चित करने के लिए करता है कि केवल Romeo
इस पद्धति को कॉल कर सकता है और जांच सकता है कि प्यार वास्तविक है ताकि रनटाइम एक फेंक देगा NullPointerException
यदि यह है null
।
अब लड़के:
package montague;
import capulet.Juliet;
public class Romeo {
public static final class Love { private Love() {} }
private static final Love love = new Love();
public static void cuddleJuliet() {
Juliet.cuddle(love);
}
}
वर्ग Romeo.Love
सार्वजनिक है, लेकिन इसका निर्माता है private
। इसलिए कोई भी इसे देख सकता है, लेकिन केवल Romeo
इसका निर्माण कर सकता है। मैं एक स्थैतिक संदर्भ का उपयोग करता हूं, इसलिए इसका Romeo.Love
उपयोग कभी नहीं किया जाता है केवल एक बार निर्माण किया जाता है और अनुकूलन को प्रभावित नहीं करता है।
इसलिए, Romeo
यह कर सकते हैं cuddle
Juliet
और केवल वह, क्योंकि केवल वह निर्माण और उपयोग कर सकते हैं कर सकते हैं एक Romeo.Love
उदाहरण है, जो के लिए आवश्यक है Juliet
करने के लिए cuddle
उसे (या किसी वह आप एक साथ थप्पड़ मारता हूँ NullPointerException
)।
Romeo
s ' Love
के लिए Julia
बदल कर अनन्त love
क्षेत्र होने के लिए final
;-)।
जावा के डिजाइनरों ने मित्र के विचार को स्पष्ट रूप से खारिज कर दिया क्योंकि यह सी ++ में काम करता है। आपने अपने "दोस्तों" को उसी पैकेज में रखा। निजी, संरक्षित और पैकेज्ड सुरक्षा को भाषा डिजाइन के हिस्से के रूप में लागू किया गया है।
जेम्स गोसलिंग चाहते थे कि जावा गलतियों के बिना C ++ हो। मेरा मानना है कि उन्होंने महसूस किया कि दोस्त एक गलती थी क्योंकि यह ओओपी सिद्धांतों का उल्लंघन करता है। पैकेज OOP के बारे में बहुत शुद्ध होने के बिना घटकों को व्यवस्थित करने का एक उचित तरीका प्रदान करते हैं।
एनआर ने बताया कि आप प्रतिबिंब का उपयोग कर धोखा दे सकते हैं, लेकिन यहां तक कि केवल तभी काम करता है यदि आप सुरक्षा प्रबंधक का उपयोग नहीं कर रहे हैं। यदि आप जावा मानक सुरक्षा को चालू करते हैं, तो आप प्रतिबिंब के साथ धोखा नहीं दे पाएंगे जब तक कि आप सुरक्षा नीति को विशेष रूप से अनुमति देने के लिए नहीं लिखते हैं।
friend
ओओपी का उल्लंघन किया था (विशेष रूप से, पैकेज एक्सेस से अधिक) तो वह वास्तव में इसे समझ नहीं पाया (पूरी तरह से संभव है, बहुत से लोग इसे गलत समझते हैं)।
जावा में 'दोस्त' की अवधारणा उपयोगी है, उदाहरण के लिए, इसके कार्यान्वयन से एपीआई को अलग करने के लिए। कार्यान्वयन कक्षाओं के लिए एपीआई क्लास इंटर्नल्स तक पहुंच की आवश्यकता होती है, लेकिन इन्हें एपीआई ग्राहकों के संपर्क में नहीं आना चाहिए। यह नीचे दिए गए विवरण के अनुसार 'फ्रेंड एक्सेसर' पैटर्न का उपयोग करके प्राप्त किया जा सकता है:
एपीआई के माध्यम से उजागर किया गया वर्ग:
package api;
public final class Exposed {
static {
// Declare classes in the implementation package as 'friends'
Accessor.setInstance(new AccessorImpl());
}
// Only accessible by 'friend' classes.
Exposed() {
}
// Only accessible by 'friend' classes.
void sayHello() {
System.out.println("Hello");
}
static final class AccessorImpl extends Accessor {
protected Exposed createExposed() {
return new Exposed();
}
protected void sayHello(Exposed exposed) {
exposed.sayHello();
}
}
}
'मित्र' कार्यक्षमता प्रदान करने वाला वर्ग:
package impl;
public abstract class Accessor {
private static Accessor instance;
static Accessor getInstance() {
Accessor a = instance;
if (a != null) {
return a;
}
return createInstance();
}
private static Accessor createInstance() {
try {
Class.forName(Exposed.class.getName(), true,
Exposed.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
return instance;
}
public static void setInstance(Accessor accessor) {
if (instance != null) {
throw new IllegalStateException(
"Accessor instance already set");
}
instance = accessor;
}
protected abstract Exposed createExposed();
protected abstract void sayHello(Exposed exposed);
}
'मित्र' कार्यान्वयन पैकेज में एक वर्ग से उदाहरण का उपयोग:
package impl;
public final class FriendlyAccessExample {
public static void main(String[] args) {
Accessor accessor = Accessor.getInstance();
Exposed exposed = accessor.createExposed();
accessor.sayHello(exposed);
}
}
आपके प्रश्न के दो समाधान हैं जो सभी वर्गों को एक ही पैकेज में रखने में शामिल नहीं हैं।
सबसे पहले फ्रेंड एक्सेसर / फ्रेंड पैकेज का उपयोग करना है पैटर्न (प्रेक्टिकल एपीआई डिज़ाइन, टुलक 2008) में वर्णित है।
दूसरा है OSGi का उपयोग करना। यहाँ एक लेख है जिसमें बताया गया है कि OSGi इसे कैसे पूरा करता है।
जहां तक मुझे पता है, यह संभव नहीं है।
हो सकता है, आप हमें अपने डिजाइन के बारे में कुछ और जानकारी दे सकें। इस तरह के प्रश्न संभवतया डिज़ाइन दोषों के परिणाम हैं।
जरा विचार करें
इरिक्मा का जवाब आसान और उत्कृष्ट है। मैं एक और बात जोड़ सकता हूं: एक सार्वजनिक रूप से सुलभ विधि होने के बजाय, एक दोस्त पाने के लिए getFriend () का उपयोग करें जिसे आप उपयोग नहीं कर सकते हैं, आप एक कदम आगे बढ़ सकते हैं और एक टोकन के बिना दोस्त को प्राप्त करने से मना कर सकते हैं: getFriend (Service.FriadToken)। यह फ्रेंडटोकेन एक निजी कंस्ट्रक्टर के साथ एक आंतरिक सार्वजनिक वर्ग होगा, ताकि केवल सेवा ही किसी को तुरंत दे सके।
यहां एक पुन: प्रयोज्य के साथ एक स्पष्ट उपयोग-मामला उदाहरण है Friend
वर्ग के । इस तंत्र का लाभ उपयोग की सादगी है। हो सकता है कि यूनिट टेस्ट कक्षाओं को बाकी एप्लिकेशन की तुलना में अधिक एक्सेस देने के लिए अच्छा हो।
शुरू करने के लिए, यहां एक उदाहरण है कि Friend
कक्षा का उपयोग कैसे किया जाए ।
public class Owner {
private final String member = "value";
public String getMember(final Friend friend) {
// Make sure only a friend is accepted.
friend.is(Other.class);
return member;
}
}
फिर दूसरे पैकेज में आप ऐसा कर सकते हैं:
public class Other {
private final Friend friend = new Friend(this);
public void test() {
String s = new Owner().getMember(friend);
System.out.println(s);
}
}
Friend
वर्ग इस प्रकार है।
public final class Friend {
private final Class as;
public Friend(final Object is) {
as = is.getClass();
}
public void is(final Class c) {
if (c == as)
return;
throw new ClassCastException(String.format("%s is not an expected friend.", as.getName()));
}
public void is(final Class... classes) {
for (final Class c : classes)
if (c == as)
return;
is((Class)null);
}
}
हालाँकि, समस्या यह है कि इसका दुरुपयोग किया जा सकता है:
public class Abuser {
public void doBadThings() {
Friend badFriend = new Friend(new Other());
String s = new Owner().getMember(badFriend);
System.out.println(s);
}
}
अब, यह सच हो सकता है कि Other
वर्ग के पास कोई सार्वजनिक निर्माता नहीं है, इसलिए उपरोक्त Abuser
कोड को असंभव बना देता है । हालांकि, अपने वर्ग करता है, तो करता है एक सार्वजनिक निर्माता है तो यह शायद उचित एक आंतरिक वर्ग के रूप में मित्र वर्ग नकल करने के लिए है। इस Other2
वर्ग को एक उदाहरण के रूप में लें :
public class Other2 {
private final Friend friend = new Friend();
public final class Friend {
private Friend() {}
public void check() {}
}
public void test() {
String s = new Owner2().getMember(friend);
System.out.println(s);
}
}
और तब Owner2
वर्ग इस तरह होगा:
public class Owner2 {
private final String member = "value";
public String getMember(final Other2.Friend friend) {
friend.check();
return member;
}
}
ध्यान दें कि Other2.Friend
कक्षा में एक निजी कंस्ट्रक्टर है, इस प्रकार यह इसे करने का एक अधिक सुरक्षित तरीका है।
प्रदान किया गया समाधान शायद सबसे सरल नहीं था। एक अन्य दृष्टिकोण C ++ के समान विचार पर आधारित है: निजी सदस्य पैकेज / निजी दायरे के बाहर सुलभ नहीं होते हैं, केवल एक विशिष्ट वर्ग को छोड़कर जो मालिक खुद का मित्र बनाता है।
जिस वर्ग को किसी सदस्य के लिए मित्र पहुंच की आवश्यकता होती है, उसे एक आंतरिक सार्वजनिक सार "मित्र वर्ग" बनाना चाहिए, जो कि छिपी हुई संपत्तियों के मालिक वर्ग पहुंच-निर्यात के तरीकों को लागू करने वाले उपवर्ग को लौटाकर, निर्यात का उपयोग कर सकता है। मित्र वर्ग की "एपीआई" विधि निजी हो सकती है, इसलिए यह उस कक्षा के बाहर सुलभ नहीं है जिसे मित्र की आवश्यकता है। इसका एकमात्र कथन एक अमूर्त संरक्षित सदस्य के लिए एक कॉल है जो निर्यात वर्ग को लागू करता है।
यहाँ कोड है:
पहला परीक्षण जो पुष्टि करता है कि यह वास्तव में काम करता है:
package application;
import application.entity.Entity;
import application.service.Service;
import junit.framework.TestCase;
public class EntityFriendTest extends TestCase {
public void testFriendsAreOkay() {
Entity entity = new Entity();
Service service = new Service();
assertNull("entity should not be processed yet", entity.getPublicData());
service.processEntity(entity);
assertNotNull("entity should be processed now", entity.getPublicData());
}
}
तब वह सेवा जिसके लिए इकाई के एक निजी सदस्य को मित्र की आवश्यकता है:
package application.service;
import application.entity.Entity;
public class Service {
public void processEntity(Entity entity) {
String value = entity.getFriend().getEntityPackagePrivateData();
entity.setPublicData(value);
}
/**
* Class that Entity explicitly can expose private aspects to subclasses of.
* Public, so the class itself is visible in Entity's package.
*/
public static abstract class EntityFriend {
/**
* Access method: private not visible (a.k.a 'friendly') outside enclosing class.
*/
private String getEntityPackagePrivateData() {
return getEntityPackagePrivateDataImpl();
}
/** contribute access to private member by implementing this */
protected abstract String getEntityPackagePrivateDataImpl();
}
}
अंत में: इकाई वर्ग जो केवल पैकेज Application.service.Service के लिए एक पैकेज निजी सदस्य के लिए अनुकूल पहुँच प्रदान करता है।
package application.entity;
import application.service.Service;
public class Entity {
private String publicData;
private String packagePrivateData = "secret";
public String getPublicData() {
return publicData;
}
public void setPublicData(String publicData) {
this.publicData = publicData;
}
String getPackagePrivateData() {
return packagePrivateData;
}
/** provide access to proteced method for Service'e helper class */
public Service.EntityFriend getFriend() {
return new Service.EntityFriend() {
protected String getEntityPackagePrivateDataImpl() {
return getPackagePrivateData();
}
};
}
}
ठीक है, मुझे मानना होगा कि यह "मित्र सेवा :: सेवा;" की तुलना में थोड़ा लंबा है लेकिन एनोटेशन का उपयोग करके संकलन-समय की जाँच को बनाए रखते हुए इसे छोटा करना संभव हो सकता है।
जावा में "पैकेज-संबंधित मित्रता" होना संभव है। यह यूनिट टेस्टिंग के लिए यूजरफुल हो सकता है। यदि आप एक विधि के सामने निजी / सार्वजनिक / संरक्षित निर्दिष्ट नहीं करते हैं, तो यह "पैकेज में मित्र" होगा। उसी पैकेज में एक क्लास इसे एक्सेस करने में सक्षम होगी, लेकिन यह क्लास के बाहर निजी होगी।
यह नियम हमेशा ज्ञात नहीं है, और यह C ++ "मित्र" कीवर्ड का एक अच्छा अनुमान है। मुझे यह एक अच्छा प्रतिस्थापन लगता है।
मुझे लगता है कि C ++ में मित्र कक्षाएं जावा में इनर-क्लास अवधारणा की तरह हैं। आंतरिक कक्षाओं का उपयोग करके आप वास्तव में एक संलग्न वर्ग और एक संलग्न को परिभाषित कर सकते हैं। संलग्न वर्ग की सार्वजनिक और निजी सदस्यों तक पूरी पहुंच है, जो इसे वर्ग को घेर रहा है। निम्नलिखित लिंक देखें: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
मुझे लगता है, मित्र एक्सेसर पैटर्न का उपयोग करने का तरीका बहुत जटिल है। मुझे उसी समस्या का सामना करना पड़ा और मैंने जावा में C ++ से ज्ञात अच्छे, पुराने कॉपी कंस्ट्रक्टर का उपयोग करके हल किया:
public class ProtectedContainer {
protected String iwantAccess;
protected ProtectedContainer() {
super();
iwantAccess = "Default string";
}
protected ProtectedContainer(ProtectedContainer other) {
super();
this.iwantAccess = other.iwantAccess;
}
public int calcSquare(int x) {
iwantAccess = "calculated square";
return x * x;
}
}
अपने आवेदन में आप निम्नलिखित कोड लिख सकते हैं:
public class MyApp {
private static class ProtectedAccessor extends ProtectedContainer {
protected ProtectedAccessor() {
super();
}
protected PrivateAccessor(ProtectedContainer prot) {
super(prot);
}
public String exposeProtected() {
return iwantAccess;
}
}
}
इस पद्धति का लाभ यह है कि केवल आपके एप्लिकेशन के पास संरक्षित डेटा तक पहुंच है। यह वास्तव में मित्र खोजशब्द का प्रतिस्थापन नहीं है। लेकिन मुझे लगता है कि जब आप कस्टम लाइब्रेरी लिखते हैं तो यह काफी उपयुक्त होता है और आपको संरक्षित डेटा एक्सेस करने की आवश्यकता होती है।
जब भी आपको ProtectedContainer के उदाहरणों से निपटना होता है तो आप अपने ProtectedAccessor को इसके चारों ओर लपेट सकते हैं और आप पहुंच प्राप्त कर सकते हैं।
यह संरक्षित विधियों के साथ भी काम करता है। आप उन्हें अपने एपीआई में संरक्षित परिभाषित करते हैं। बाद में आपके आवेदन में आप एक निजी रैपर क्लास लिखते हैं और संरक्षित पद्धति को सार्वजनिक करते हैं। बस।
ProtectedContainer
पैकेज के बाहर उपवर्ग किया जा सकता है!
यदि आप संरक्षित विधियों का उपयोग करना चाहते हैं, तो आप उस वर्ग का उपवर्ग बना सकते हैं जिसका आप उपयोग करना चाहते हैं जो उन तरीकों को उजागर करता है जिन्हें आप सार्वजनिक रूप से उपयोग करना चाहते हैं (या आंतरिक नाम के लिए सुरक्षित होना चाहते हैं), और आपके वर्ग में उस वर्ग का एक उदाहरण है (इसे एक छद्म के रूप में उपयोग करें)।
जहां तक निजी तरीकों का सवाल है (मुझे लगता है) आप भाग्य से बाहर हैं।
मैं मानता हूं कि ज्यादातर मामलों में मित्र कीवर्ड अनावश्यक है।
और अंत में, यदि यह वास्तव में आवश्यक है, तो अन्य उत्तरों में उल्लिखित मित्र एक्सेसर पैटर्न है।
इस समस्या को हल करने के लिए मैंने एक तरीका खोजा है, एक एक्सेसर ऑब्जेक्ट बनाने के लिए, जैसे:
class Foo {
private String locked;
/* Anyone can get locked. */
public String getLocked() { return locked; }
/* This is the accessor. Anyone with a reference to this has special access. */
public class FooAccessor {
private FooAccessor (){};
public void setLocked(String locked) { Foo.this.locked = locked; }
}
private FooAccessor accessor;
/** You get an accessor by calling this method. This method can only
* be called once, so calling is like claiming ownership of the accessor. */
public FooAccessor getAccessor() {
if (accessor != null)
throw new IllegalStateException("Cannot return accessor more than once!");
return accessor = new FooAccessor();
}
}
कॉल करने वाला पहला कोड getAccessor()
एक्सेसर के "स्वामित्व का दावा करता है"। आमतौर पर, यह कोड है जो ऑब्जेक्ट बनाता है।
Foo bar = new Foo(); //This object is safe to share.
FooAccessor barAccessor = bar.getAccessor(); //This one is not.
यह भी, क्योंकि यह एक पर पहुंच को सीमित करते करने की अनुमति देता से अधिक सी ++ के दोस्त तंत्र एक फायदा है प्रति-उदाहरण के रूप में एक करने का विरोध किया, स्तर प्रति वर्ग स्तर। एक्सेसर संदर्भ को नियंत्रित करके, आप ऑब्जेक्ट तक पहुंच को नियंत्रित करते हैं। आप कई एक्सेसर्स भी बना सकते हैं, और प्रत्येक को अलग-अलग एक्सेस दे सकते हैं, जो इस बात पर ठीक-ठीक नियंत्रण देता है कि कौन सा कोड क्या एक्सेस कर सकता है:
class Foo {
private String secret;
private String locked;
/* Anyone can get locked. */
public String getLocked() { return locked; }
/* Normal accessor. Can write to locked, but not read secret. */
public class FooAccessor {
private FooAccessor (){};
public void setLocked(String locked) { Foo.this.locked = locked; }
}
private FooAccessor accessor;
public FooAccessor getAccessor() {
if (accessor != null)
throw new IllegalStateException("Cannot return accessor more than once!");
return accessor = new FooAccessor();
}
/* Super accessor. Allows access to secret. */
public class FooSuperAccessor {
private FooSuperAccessor (){};
public String getSecret() { return Foo.this.secret; }
}
private FooSuperAccessor superAccessor;
public FooSuperAccessor getAccessor() {
if (superAccessor != null)
throw new IllegalStateException("Cannot return accessor more than once!");
return superAccessor = new FooSuperAccessor();
}
}
अंत में, यदि आप चीजों को थोड़ा और व्यवस्थित करना चाहते हैं, तो आप एक संदर्भ वस्तु बना सकते हैं, जो सब कुछ एक साथ रखती है। यह आपको सभी एक्सेसरों को एक विधि कॉल के साथ दावा करने की अनुमति देता है, साथ ही साथ उन्हें उनके जुड़े उदाहरण के साथ रखता है। एक बार आपके पास संदर्भ हो जाने पर, आप एक्सेसर्स को उस कोड के पास भेज सकते हैं, जिसे इसकी आवश्यकता है:
class Foo {
private String secret;
private String locked;
public String getLocked() { return locked; }
public class FooAccessor {
private FooAccessor (){};
public void setLocked(String locked) { Foo.this.locked = locked; }
}
public class FooSuperAccessor {
private FooSuperAccessor (){};
public String getSecret() { return Foo.this.secret; }
}
public class FooReference {
public final Foo foo;
public final FooAccessor accessor;
public final FooSuperAccessor superAccessor;
private FooReference() {
this.foo = Foo.this;
this.accessor = new FooAccessor();
this.superAccessor = new FooSuperAccessor();
}
}
private FooReference reference;
/* Beware, anyone with this object has *all* the accessors! */
public FooReference getReference() {
if (reference != null)
throw new IllegalStateException("Cannot return reference more than once!");
return reference = new FooReference();
}
}
बहुत सिर-पीटने के बाद (अच्छी तरह से नहीं), यह मेरा अंतिम समाधान था, और मुझे यह बहुत पसंद है। यह लचीला है, उपयोग करने में सरल है, और कक्षा की पहुंच पर बहुत अच्छे नियंत्रण की अनुमति देता है। ( संदर्भ के साथ केवल पहुंच बहुत उपयोगी है।) यदि आप एक्सेसर्स / संदर्भों के लिए निजी के बजाय संरक्षित का उपयोग करते हैं, तो फू के उप-वर्ग भी विस्तारित संदर्भ वापस कर सकते हैं getReference
। इसके लिए किसी भी प्रतिबिंब की आवश्यकता नहीं होती है, इसलिए इसका उपयोग किसी भी वातावरण में किया जा सकता है।
मैं इसे सार्वजनिक वर्ग बनाने से बचने के लिए प्रतिनिधिमंडल या रचना या फैक्ट्री क्लास (इस समस्या के परिणामस्वरूप होने वाली समस्या के आधार पर) को प्राथमिकता देता हूं।
यदि यह "इंटरफ़ेस / कार्यान्वयन कक्षाएं विभिन्न पैकेजों में" समस्या है, तो मैं एक सार्वजनिक कारखाना वर्ग का उपयोग करूंगा जो कि निहित पैकेज के समान पैकेज में होगा और अंतर्निहित वर्ग के जोखिम को रोक देगा।
यदि यह "मुझे इस वर्ग / पद्धति को सार्वजनिक करने से नफरत है, तो यह एक अलग पैकेज में किसी अन्य वर्ग के लिए यह कार्यक्षमता प्रदान करने के लिए" समस्या है, तो मैं एक ही पैकेज में एक सार्वजनिक प्रतिनिधि वर्ग का उपयोग करूंगा और कार्यक्षमता के केवल उस हिस्से को उजागर करूंगा "बाहरी व्यक्ति" वर्ग द्वारा आवश्यक।
इनमें से कुछ निर्णय लक्ष्य सर्वर क्लास लोडिंग आर्किटेक्चर (ओएसजीआई बंडल, डब्ल्यूएआर / ईएआर, आदि), तैनाती और पैकेज नामकरण सम्मेलनों द्वारा संचालित होते हैं। उदाहरण के लिए, उपरोक्त प्रस्तावित समाधान, सामान्य जावा अनुप्रयोगों के लिए 'फ्रेंड एक्सेसर' पैटर्न चतुर है। मुझे आश्चर्य है कि अगर क्लासॉस्टिंग स्टाइल में अंतर के कारण इसे ओएसजीआई में लागू करने के लिए मुश्किल हो जाता है।
मुझे नहीं पता कि यह किसी के लिए किसी काम का है या नहीं, लेकिन मैंने इसे निम्नलिखित तरीके से संभाला:
मैंने एक इंटरफ़ेस (व्यवस्थापन) बनाया।
हर वर्ग जो कॉल करने में सक्षम होना चाहिए कहा गया है कि कार्यों को लागू करना चाहिए।
फिर मैंने एक फ़ंक्शन HasAdminRights को इस प्रकार बनाया:
private static final boolean HasAdminRights()
{
// Gets the current hierarchy of callers
StackTraceElement[] Callers = new Throwable().getStackTrace();
// Should never occur with me but if there are less then three StackTraceElements we can't check
if (Callers.length < 3)
{
EE.InvalidCode("Couldn't check for administrator rights");
return false;
} else try
{
// Now we check the third element as this function is the first and the function wanting to check for the rights the second. We try to use it as a subclass of AdminRights.
Class.forName(Callers[2].getClassName()).asSubclass(AdminRights.class);
// If everything worked up to now, it has admin rights!
return true;
} catch (java.lang.ClassCastException | ClassNotFoundException e)
{
// In the catch, something went wrong and we can deduce that the caller has no admin rights
EE.InvalidCode(Callers[1].getClassName() + " doesn't have administrator rights");
return false;
}
}