Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a constructor available to only the factory class?

Ok, the question might not be crystal clear. Let me give some details:

Let's say I have an Shoe (CShoe) object factory class called CFactory. CFactory is a singleton class that creates and stores all instanciated shoes using a simple hashmap. It is then accessed through static methods to use the created objects.

Is there a way to force CShoe's constructor so that it can only called by the factory? (in other words, ensure that the creation of shoes can only be done by the shoes factory singleton class and not by other classes)

like image 996
koni Avatar asked May 27 '09 09:05

koni


People also ask

Do constructors always have to be public?

No, Constructors can be public , private , protected or default (no access modifier at all). Making something private doesn't mean nobody can access it. It just means that nobody outside the class can access it. So private constructor is useful too.

When would you use a factory constructor?

A factory constructor is a constructor that can be used when you don't necessarily want a constructor to create a new instance of your class. This might be useful if you hold instances of your class in memory and don't want to create a new one each time (or if the operation of creating an instance is costly).

Is a constructor a factory?

A constructor is concrete in that it creates objects as instances of a single class, and by a specified process (class instantiation), while a factory can create objects by instantiating various classes, or by using other allocation schemes such as an object pool.


4 Answers

You could make Shoe an inner class of ShoeFactory:

public class ShoeFactory {

    public static class Shoe {
        private String name;

        private Shoe() {
        }

        private Shoe(String name) {
            this.name = name;
        }
    }

    public static Shoe createShoe(String shoeName) {
        return new Shoe(shoeName);
    }
}

I think this pretty much covers all the cases except .... reflection:

public class SmellyShoe {

    public static void main(String[] args) {
        try {
            java.lang.reflect.Constructor c = Shoe.class.getDeclaredConstructors()[0];
            c.setAccessible(true);
            Shoe smelly = (Shoe)c.newInstance(null);
            // grr
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
like image 164
bruno conde Avatar answered Oct 07 '22 15:10

bruno conde


You could give the CShoe constructor package access, and put both CShoe and CFactory in the same package.

like image 36
Igor Krivokon Avatar answered Oct 07 '22 15:10

Igor Krivokon


Since you want to add each object to the map you could as well move this logic to the CShoe constructor - the object will add itsself.

like image 41
sharptooth Avatar answered Oct 07 '22 13:10

sharptooth


Firstly, if you retain all created instances, that's known as a leak. I'll carry on assuming you mean a non-strong reference, bounded or some such cache, and also that Shoe is immutable.

Simply use a static method to return the factory.

public final class Shoe implements Footwear {
    private static final FootwearFactory<Shoe,Something> FACTORY =
        new FootwearFactory<Shoe,Something>() {
            ...
            public Shoe get(Something value) {
                value = new Something(value);
                ...
                return new Show(value);
            }
        };
    private static FootwearFactory<Shoe,Something> getFactory() {
        return FACTORY;
    }

    private final Something value;
    private Shoe(Something value) {
        this.value = value;
    }
    ...
}
like image 41
Tom Hawtin - tackline Avatar answered Oct 07 '22 14:10

Tom Hawtin - tackline