হ্যাঁ, ব্যবহার করুন HashMap... তবে বিশেষায়িত উপায়ে: যে ছন্দটি আমি HashMapছদ্ম হিসাবে ব্যবহার করার চেষ্টা করেছিলাম - সেগুলির Set"প্রকৃত" উপাদান Map/Setএবং "প্রার্থী" উপাদানগুলির মধ্যে সম্ভাব্য বিভ্রান্তি , অর্থাৎ উপাদানগুলি পরীক্ষা করার জন্য ব্যবহৃত হয় কিনা equalউপাদান ইতিমধ্যে উপস্থিত। এটি নির্বোধ থেকে দূরে, তবে আপনাকে ফাঁদ থেকে দূরে সরিয়ে দেয়:
class SelfMappingHashMap<V> extends HashMap<V, V>{
@Override
public String toString(){
// otherwise you get lots of "... object1=object1, object2=object2..." stuff
return keySet().toString();
}
@Override
public V get( Object key ){
throw new UnsupportedOperationException( "use tryToGetRealFromCandidate()");
}
@Override
public V put( V key, V value ){
// thorny issue here: if you were indavertently to `put`
// a "candidate instance" with the element already in the `Map/Set`:
// these will obviously be considered equivalent
assert key.equals( value );
return super.put( key, value );
}
public V tryToGetRealFromCandidate( V key ){
return super.get(key);
}
}
তারপরে এটি করুন:
SelfMappingHashMap<SomeClass> selfMap = new SelfMappingHashMap<SomeClass>();
...
SomeClass candidate = new SomeClass();
if( selfMap.contains( candidate ) ){
SomeClass realThing = selfMap.tryToGetRealFromCandidate( candidate );
...
realThing.useInSomeWay()...
}
তবে ... আপনি এখন candidateকোনও উপায়ে আত্ম-বিনষ্ট করতে চান যদি না প্রোগ্রামার প্রকৃতপক্ষে তা অবিলম্বে রাখে Map/Set... আপনি contains"কলঙ্কিত" করতে চাইবেন candidateযাতে এটির সাথে যুক্ত না হওয়া পর্যন্ত এটির কোনও ব্যবহার Map"অ্যানথেমা" না করে "। সম্ভবত আপনি SomeClassএকটি নতুন Taintableইন্টারফেস বাস্তবায়ন করতে পারে ।
আরও সন্তোষজনক সমাধান নীচে যেমন একটি গেটেবল সেট । যাইহোক, এটি কাজ SomeClassকরার জন্য আপনাকে সমস্ত নির্মাতাকে অ-দৃশ্যমান করার জন্য (বা ... সক্ষম এবং এটির জন্য একটি র্যাপার ক্লাস ব্যবহার করতে সক্ষম) করার জন্য ডিজাইনের দায়িত্বে থাকতে হবে:
public interface NoVisibleConstructor {
// again, this is a "nudge" technique, in the sense that there is no known method of
// making an interface enforce "no visible constructor" in its implementing classes
// - of course when Java finally implements full multiple inheritance some reflection
// technique might be used...
NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet );
};
public interface GettableSet<V extends NoVisibleConstructor> extends Set<V> {
V getGenuineFromImpostor( V impostor ); // see below for naming
}
বাস্তবায়ন:
public class GettableHashSet<V extends NoVisibleConstructor> implements GettableSet<V> {
private Map<V, V> map = new HashMap<V, V>();
@Override
public V getGenuineFromImpostor(V impostor ) {
return map.get( impostor );
}
@Override
public int size() {
return map.size();
}
@Override
public boolean contains(Object o) {
return map.containsKey( o );
}
@Override
public boolean add(V e) {
assert e != null;
V result = map.put( e, e );
return result != null;
}
@Override
public boolean remove(Object o) {
V result = map.remove( o );
return result != null;
}
@Override
public boolean addAll(Collection<? extends V> c) {
// for example:
throw new UnsupportedOperationException();
}
@Override
public void clear() {
map.clear();
}
// implement the other methods from Set ...
}
আপনার NoVisibleConstructorক্লাসগুলি তখন এর মতো দেখায়:
class SomeClass implements NoVisibleConstructor {
private SomeClass( Object param1, Object param2 ){
// ...
}
static SomeClass getOrCreate( GettableSet<SomeClass> gettableSet, Object param1, Object param2 ) {
SomeClass candidate = new SomeClass( param1, param2 );
if (gettableSet.contains(candidate)) {
// obviously this then means that the candidate "fails" (or is revealed
// to be an "impostor" if you will). Return the existing element:
return gettableSet.getGenuineFromImpostor(candidate);
}
gettableSet.add( candidate );
return candidate;
}
@Override
public NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet ){
// more elegant implementation-hiding: see below
}
}
PS যেমন একটি NoVisibleConstructorশ্রেণীর সাথে একটি প্রযুক্তিগত সমস্যা : এটি আপত্তি করা যেতে পারে যে এই জাতীয় শ্রেণিটি সহজাতভাবে final, যা অনাকাঙ্ক্ষিত হতে পারে। আসলে আপনি সর্বদা একটি ডামি প্যারামিটারলেস protectedকনস্ট্রাক্টর যুক্ত করতে পারেন :
protected SomeClass(){
throw new UnsupportedOperationException();
}
... যা কমপক্ষে একটি সাবক্লাস সংকলন করতে দেয়। এরপরে আপনাকে getOrCreate()সাবক্লাসে আরও একটি কারখানার পদ্ধতি অন্তর্ভুক্ত করতে হবে কিনা তা ভাবতে হবে ।
চূড়ান্ত পদক্ষেপ হ'ল একটি বিমূর্ত বেস ক্লাস (কোনও তালিকার জন্য এনবি "উপাদান", একটি সেটের জন্য "সদস্য") আপনার সেট সদস্যদের জন্য এটি (যখন সম্ভব হয় - আবার, যেখানে ক্লাসটি আপনার নিয়ন্ত্রণে নেই এমন একটি মোড়কের ক্লাস ব্যবহারের সুযোগ রয়েছে , বা ইতিমধ্যে একটি বেস ক্লাস ইত্যাদি রয়েছে), সর্বাধিক বাস্তবায়ন-আড়াল করার জন্য:
public abstract class AbstractSetMember implements NoVisibleConstructor {
@Override
public NoVisibleConstructor
addOrGetExisting(GettableSet<? extends NoVisibleConstructor> gettableSet) {
AbstractSetMember member = this;
@SuppressWarnings("unchecked") // unavoidable!
GettableSet<AbstractSetMembers> set = (GettableSet<AbstractSetMember>) gettableSet;
if (gettableSet.contains( member )) {
member = set.getGenuineFromImpostor( member );
cleanUpAfterFindingGenuine( set );
} else {
addNewToSet( set );
}
return member;
}
abstract public void addNewToSet(GettableSet<? extends AbstractSetMember> gettableSet );
abstract public void cleanUpAfterFindingGenuine(GettableSet<? extends AbstractSetMember> gettableSet );
}
... ব্যবহার মোটামুটি সুস্পষ্ট (আপনার ভিতরে SomeClass'র staticকারখানা পদ্ধতি):
SomeClass setMember = new SomeClass( param1, param2 ).addOrGetExisting( set );
SortedSetএবং এর প্রয়োগগুলি, যা মানচিত্র ভিত্তিক (যেমনTreeSetঅ্যাক্সেসের অনুমতি দেয়first())।