হ্যাঁ, ব্যবহার করুন 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()
)।