আমি একটি প্যাকেজে জাভা ক্লাস লিখতে সক্ষম হতে চাই যা অন্য শ্রেণীর সাবক্লাস না করে অন্য প্যাকেজে কোনও শ্রেণীর অ-সর্বজনীন পদ্ধতিতে অ্যাক্সেস করতে পারে। এটা কি সম্ভব?
আমি একটি প্যাকেজে জাভা ক্লাস লিখতে সক্ষম হতে চাই যা অন্য শ্রেণীর সাবক্লাস না করে অন্য প্যাকেজে কোনও শ্রেণীর অ-সর্বজনীন পদ্ধতিতে অ্যাক্সেস করতে পারে। এটা কি সম্ভব?
উত্তর:
এখানে আমি একটি ছোট ট্রিকস যা আমি জাভাতে সি ++ বন্ধুতন্ত্রের প্রতিরূপ তৈরি করতে ব্যবহার করি।
বলি আমার একটি ক্লাস Romeo
এবং অন্য ক্লাস রয়েছে Juliet
। তারা বিদ্বেষের কারণে বিভিন্ন প্যাকেজে (পরিবার) থাকে।
Romeo
চায় cuddle
Juliet
এবং Juliet
কেবল তাকেই দিতে চায় Romeo
cuddle
।
সি ++ এ, (প্রেমিক) হিসাবে 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 ++ এ কাজ করার কারণে স্পষ্টভাবে প্রত্যাখ্যান করেছিল। আপনি আপনার "বন্ধুরা" একই প্যাকেজে রেখেছেন। ভাষা, নকশার অংশ হিসাবে ব্যক্তিগত, সুরক্ষিত এবং প্যাকেজযুক্ত সুরক্ষা প্রয়োগ করা হয়েছে।
জেমস গোসলিং চেয়েছিলেন জাভাটি ভুল ছাড়াই সি ++ হওয়া উচিত। আমি বিশ্বাস করি যে তিনি বন্ধুটিকে ভুল বলে মনে করেছিলেন কারণ এটি ওওপি নীতিগুলি লঙ্ঘন করে। প্যাকেজগুলি ওওপি সম্পর্কে খুব খাঁটি না হয়ে উপাদানগুলি সংগঠিত করার যুক্তিসঙ্গত উপায় সরবরাহ করে।
এনআর উল্লেখ করেছে যে আপনি প্রতিবিম্ব ব্যবহার করে প্রতারণা করতে পারেন, তবে এটি কেবলমাত্র যদি আপনি সিকিউরিটি ম্যানেজার ব্যবহার না করেন তবে কাজ করে। আপনি যদি জাভা স্ট্যান্ডার্ড সুরক্ষা চালু করেন তবে আপনি সুনির্দিষ্টভাবে অনুমতি দেওয়ার জন্য সুরক্ষা নীতি না লিখলে আপনি প্রতিচ্ছবি দিয়ে প্রতারণা করতে পারবেন না।
friend
ওওপি লঙ্ঘন করেছে (বিশেষত, প্যাকেজ অ্যাক্সেসের চেয়ে বেশি) তবে সে সত্যই তা বুঝতে পারে না (সম্পূর্ণ সম্ভব, অনেক লোক এটি ভুল বোঝে )।
জাভাতে 'বন্ধু' ধারণাটি কার্যকর, উদাহরণস্বরূপ, এর প্রয়োগ থেকে একটি এপিআই আলাদা করতে। প্রয়োগকারী ক্লাসগুলির জন্য এপিআই শ্রেণির অভ্যন্তরীণ প্রবেশাধিকার প্রয়োজন তবে এটি এপিআই ক্লায়েন্টের কাছে প্রকাশ করা উচিত নয়। নীচে বিস্তারিত হিসাবে 'বন্ধু অ্যাকসেসর' প্যাটার্নটি ব্যবহার করে এটি অর্জন করা যেতে পারে:
ক্লাসটি API এর মাধ্যমে উন্মুক্ত:
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);
}
}
আপনার প্রশ্নের দুটি সমাধান রয়েছে যা সমস্ত ক্লাসকে একই প্যাকেজে রাখার সাথে জড়িত না।
প্রথমটি হ'ল (ব্যবহারিক এপিআই ডিজাইন, তুলাক ২০০৮) বর্ণিত ফ্রেন্ড অ্যাকসেসর / ফ্রেন্ড প্যাকেজ প্যাটার্নটি ব্যবহার করা ।
দ্বিতীয়টি হল ওএসজিআই ব্যবহার করা। ওএসজি এটি কীভাবে সম্পাদন করে তা ব্যাখ্যা করে এখানে একটি নিবন্ধ রয়েছে ।
আমি যতদূর জানি, এটি সম্ভব নয়।
হতে পারে, আপনি আমাদের আপনার নকশা সম্পর্কে আরও কিছু বিবরণ দিতে পারেন। এই জাতীয় প্রশ্নগুলি সম্ভবত নকশার ত্রুটির ফলাফল।
শুধু বিবেচনা করুন
eirikma এর উত্তর সহজ এবং দুর্দান্ত। আমি আরও একটি জিনিস যুক্ত করতে পারি: জনসাধারণের অ্যাক্সেসযোগ্য পদ্ধতি না থাকার পরিবর্তে, এমন বন্ধুটি পাওয়ার জন্য getFender () ব্যবহার করুন যা আপনি ব্যবহার করতে পারবেন না, আপনি একধাপ এগিয়ে যেতে পারেন এবং টোকেন ছাড়াই বন্ধুটি পেতে অস্বীকার করতে পারেন: getFender (Service.FenderToken)। এই ফ্রেন্ডটোকনটি কোনও প্রাইভেট কনস্ট্রাক্টরের সাথে অভ্যন্তরীণ পাবলিক ক্লাস হবে, যাতে কেবল পরিষেবাটি কোনওটিকে তাত্পর্যপূর্ণ করতে পারে।
পুনরায় ব্যবহারযোগ্য 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 ++ এর মত একই ধারণার উপর ভিত্তি করে আরেকটি পদ্ধতি: ব্যক্তিগত সদস্যরা প্যাকেজ / ব্যক্তিগত সুযোগের বাইরে অ্যাক্সেসযোগ্য না, নির্দিষ্ট শ্রেণি ব্যতীত যে মালিক তার নিজের বন্ধু তৈরি করে।
যে শ্রেণীর সদস্যের সদস্যের অ্যাক্সেস প্রয়োজন, সেই শ্রেণীর এমন একটি অভ্যন্তরীণ পাবলিক অ্যাবস্ট্রাক্ট "ফ্রেন্ড ক্লাস" তৈরি করা উচিত যা গোপন সংস্থাগুলির মালিকানাধীন শ্রেণি অ্যাক্সেস-বাস্তবায়ন পদ্ধতি প্রয়োগ করে এমন একটি সাবক্লাস ফিরে দিয়ে to বন্ধু শ্রেণীর "এপিআই" পদ্ধতিটি ব্যক্তিগত হতে পারে তাই শ্রেণীর বাইরে এটি অ্যাক্সেসযোগ্য নয় যার জন্য বন্ধুর অ্যাক্সেস প্রয়োজন। এর একমাত্র বিবৃতিটি একটি বিমূর্ত সুরক্ষিত সদস্যকে কল যা রফতানিকারী শ্রেণি প্রয়োগ করে।
কোডটি এখানে:
প্রথম পরীক্ষা যা যাচাই করে যে এটি আসলে কাজ করে:
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();
}
}
শেষ অবধি: সত্তা শ্রেণি যা কেবলমাত্র ক্লাস অ্যাপ্লিকেশন.সার্ভিস.সোর্সিতে প্যাকেজ ব্যক্তিগত সদস্যের জন্য বন্ধুত্বপূর্ণ অ্যাক্সেস সরবরাহ করে।
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();
}
};
}
}
ঠিক আছে, আমি অবশ্যই এটি স্বীকার করতে হবে "বন্ধু পরিষেবা :: পরিষেবা" এর চেয়ে কিছুটা দীর্ঘ তবে টীকাগুলি ব্যবহার করে সংকলন-সময় পরীক্ষা চালিয়ে যাওয়ার সময় এটি সংক্ষিপ্ত করা সম্ভব হতে পারে।
জাভাতে একটি "প্যাকেজ-সম্পর্কিত বন্ধুত্ব" থাকা সম্ভব। এটি ইউনিট পরীক্ষার জন্য দরকারী হতে পারে। যদি আপনি কোনও পদ্ধতির সামনে ব্যক্তিগত / পাবলিক / সুরক্ষিত নির্দিষ্ট না করেন তবে এটি "প্যাকেজের বন্ধু" হবে। একই প্যাকেজের কোনও শ্রেণি এটি অ্যাক্সেস করতে সক্ষম হবে তবে এটি শ্রেণীর বাইরে ব্যক্তিগত হবে।
এই নিয়মটি সর্বদা জানা যায় না এবং এটি একটি সি ++ "বন্ধু" কীওয়ার্ডের একটি ভাল অনুমিতিকরণ। আমি এটি একটি ভাল প্রতিস্থাপন খুঁজে।
আমি মনে করি যে সি ++ এ বন্ধুত্বপূর্ণ ক্লাসগুলি জাভাতে অভ্যন্তর-শ্রেণীর ধারণার মতো। অভ্যন্তরীণ-শ্রেণীর ব্যবহার করে আপনি প্রকৃতপক্ষে একটি বদ্ধ শ্রেণি এবং একটি বদ্ধ শ্রেণীর সংজ্ঞা দিতে পারেন। বদ্ধ ক্লাসের এর ঘেরযুক্ত শ্রেণীর সরকারী এবং ব্যক্তিগত সদস্যদের কাছে সম্পূর্ণ অ্যাক্সেস রয়েছে। নিম্নলিখিত লিঙ্কটি দেখুন: http://docs.oracle.com/javase/torial/java/javaOO/nested.html
আমি মনে করি, বন্ধুর অ্যাকসেসর প্যাটার্নটি ব্যবহার করার পদ্ধতিটি খুব জটিল। আমাকে একই সমস্যার মুখোমুখি হতে হয়েছিল এবং আমি জাভাতে সি ++ থেকে পরিচিত ভাল, পুরানো অনুলিপি নির্মাণকারী ব্যবহার করে সমাধান করেছি:
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
প্যাকেজের বাইরে সাবক্ল্যাস করা যাবে!
আপনি যদি সুরক্ষিত পদ্ধতিগুলি অ্যাক্সেস করতে চান তবে আপনি যে শ্রেণীর ব্যবহার করতে চান তার একটি সাবক্লাস তৈরি করতে পারেন যা আপনি পাবলিক হিসাবে ব্যবহার করতে চান এমন পদ্ধতিগুলি (বা নামস্থানের অভ্যন্তরীণ নিরাপদ হতে অভ্যন্তরীণ) প্রকাশ করে এবং আপনার শ্রেণিতে সেই শ্রেণীর উদাহরণ রয়েছে (এটি প্রক্সি হিসাবে ব্যবহার করুন)।
যতদূর ব্যক্তিগত পদ্ধতি সম্পর্কিত (আমার মনে হয়) আপনি ভাগ্যের বাইরে।
আমি সম্মত হই যে বেশিরভাগ ক্ষেত্রে বন্ধুর কীওয়ার্ড অপ্রয়োজনীয়।
এবং পরিশেষে, যদি এটি সত্যিই প্রয়োজন হয় তবে অন্যান্য উত্তরগুলিতে উল্লিখিত বন্ধুর অ্যাকসেসর প্যাটার্ন রয়েছে।
কোনও কীওয়ার্ড বা ব্যবহার না করে।
আপনি প্রতিবিম্ব ইত্যাদি ব্যবহার করে "প্রতারণা" করতে পারেন তবে আমি "প্রতারণা" করার পরামর্শ দেব না।
এই সমস্যাটি সমাধান করার জন্য আমি যে পদ্ধতিটি পেয়েছি সেটি হ'ল একটি অ্যাক্সেসর অবজেক্ট তৈরি করা, যেমন:
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
। এটিতে কোনও প্রতিচ্ছবি প্রয়োজন হয় না, সুতরাং এটি যে কোনও পরিবেশে ব্যবহার করা যেতে পারে।
আমি এটিকে পাবলিক ক্লাস না করে এড়াতে প্রতিনিধি বা সংমিশ্রণ বা কারখানার শ্রেণি (এই সমস্যাটির ফলাফলের উপর নির্ভর করে) পছন্দ করি।
যদি এটি "বিভিন্ন প্যাকেজগুলিতে ইন্টারফেস / বাস্তবায়ন ক্লাস" সমস্যা হয় তবে আমি এমন একটি পাবলিক ফ্যাক্টরি ক্লাস ব্যবহার করব যা ইমপ্লের প্যাকেজের মতো একই প্যাকেজে থাকবে এবং ইমপ্লের ক্লাসের এক্সপোজার প্রতিরোধ করবে।
যদি এটি "অন্য শ্রেণীর জন্য অন্য কোনও প্যাকেজের জন্য এই কার্যকারিতাটি সরবরাহ করার জন্য আমি এই শ্রেণি / পদ্ধতিটিকে জনসাধারণ্যে ঘৃণা করি" তবে আমি একই প্যাকেজে একজন পাবলিক প্রতিনিধি শ্রেণি ব্যবহার করব এবং কার্যকারিতার কেবলমাত্র সেই অংশটিই প্রকাশ করব would "বহিরাগত" শ্রেণীর দ্বারা প্রয়োজনীয়।
এর মধ্যে কয়েকটি সিদ্ধান্ত লক্ষ্য সার্ভারের ক্লাসলোডিং আর্কিটেকচার (ওএসজিআই বান্ডেল, ওয়ার / ইএআর, ইত্যাদি), স্থাপনা এবং প্যাকেজ নামকরণ কনভেনশন দ্বারা চালিত হয়। উদাহরণস্বরূপ, উপরের প্রস্তাবিত সমাধান, 'ফ্রেন্ড অ্যাকসেসর' প্যাটার্নটি সাধারণ জাভা অ্যাপ্লিকেশনগুলির জন্য চালাক। ক্লাসলোডিং শৈলীর পার্থক্যের কারণে এটি OSGi এ বাস্তবায়ন করা যদি কঠিন হয়ে যায় তবে আমি ভাবছি।
এটি কারওর উপকারে আছে কিনা তা আমি জানি না তবে আমি এটি নিম্নলিখিত পদ্ধতিতে পরিচালনা করেছি:
আমি একটি ইন্টারফেস তৈরি করেছি (অ্যাডমিনাইট)।
ফাংশনগুলিতে কল করতে সক্ষম হওয়া উচিত এমন প্রতিটি শ্রেণীর অ্যাডমিনরাটগুলি প্রয়োগ করা উচিত।
তারপরে আমি নিম্নরূপে একটি ফাংশন 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;
}
}