Search code examples
javasingletonsingle-instanceobject-composition

Creating many objects using composition when the containing class is a singleton pattern


java version 1.7.0_65

I have a singleton design pattern class. That will always return the same instance that is initially created.

However, the problem I have is this class needs to create many other objects from another class. I have used composition for this (instance of POI class in ArlabFacade). From this singleton instance the client should be able to create many POI objects. And I don't want to expose the internal workings of the POI class, everything has to go through the singleton instance.

private static ArlabFacade mArlabFacade = null;
private POI mPoi; /* Should be able to create many object of this class */

private ArlabFacade(Context context) {     
        /* initialize properties */
        mContext = context;

        mPoi = null;
    }

public static ArlabFacade getInstance(Context context) {

        /* Create a synchronised singleton instance */
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        if(mArlabFacade == null) {
            mArlabFacade = new ArlabFacade(context);
        }
        lock.unlock();

        return mArlabFacade;
    }

I have tried doing something like this, but it has 2 problems.

1) I don't want to return the class instance of POI
2) because I only have a single instance the mPoi will be overwritten by the next client call to this function. 

This function will just overwrite:

 public POI createNewPOI() {
        return mPoi = new POI();
    }

Is there any design patterns that address this problem?


Solution

  • Quite simple, but first of all, please note, that lock must be created within the static context, so that every thread will use the same lock instance (there will be no synchronization at all if using the different instance for each thread)

    Now, here is the code

    public class ArlabFacade {
    
        private static ArlabFacade mArlabFacade = null;
    
        /* Create a synchronised singleton instance */
        private static final ReentrantLock lock = new ReentrantLock();
    
        private ArlabFacade(Context context) {     
            /* initialize properties */
            mContext = context;
        }
    
        public static ArlabFacade getInstance(Context context) {
            lock.lock();
            if(mArlabFacade == null) {
                mArlabFacade = new ArlabFacade(context);
            }
            lock.unlock();
            return mArlabFacade;
        }
    
        public NotAPOI createNewPOI() {
            return new NotAPOIImpl(new POI());
        }
    
        public void doSomething(NotAPOI val) {
            if(!(val instanceof NotAPOIImpl)) {
                throw new IllegalArgumentException("Illegal implementation of NotAPOI");
            }
            NotAPOIImpl impl = (NotAPOIImpl) val;
            POI poi = val.poi;
            // do something with poi here
        }
    
        private static class NotAPOIImpl implements NotAPOI {
            private POI poi;
            private NotAPOIImpl(POI poi) {
                this.poi = poi;
            }
        }
    }
    
    // As you don't like to expose the POI just hide it behind the interface
    public interface NotAPOI {
    
    }
    

    Another possible solution is to allow to work with POI by means of one more level of abstraction, which is more elegant

    public class ArlabFacade {
    
        private static ArlabFacade mArlabFacade = null;
    
        /* Create a synchronised singleton instance */
        private static final ReentrantLock lock = new ReentrantLock();
    
        private ArlabFacade(Context context) {     
            /* initialize properties */
            mContext = context;
        }
    
        public static ArlabFacade getInstance(Context context) {
            lock.lock();
            if(mArlabFacade == null) {
                mArlabFacade = new ArlabFacade(context);
            }
            lock.unlock();
            return mArlabFacade;
        }
    
        public NotAPOI createNewPOI() {
            return new NotAPOIImpl(new POI());
        }
    
        private static class NotAPOIImpl implements NotAPOI {
            private POI poi;
            private NotAPOIImpl(POI poi) {
                this.poi = poi;
            }
            public void doSomething() {
                poi.doSomething();
            }
        }
    }
    
    // As you don't like to expose the POI just hide it behind the interface
    public interface NotAPOI {
        void doSomething();
    }