views:

2073

answers:

4

I've been trying to create a factory (in Java) that prohibits subclassing of the factory product and prevents the concrete factories from being used by anyone except the abstract factory. What do you think of this...

class Client
{
    public static void main(String[] args)
    {
        Animal animal = Animal.create(Lion.class);
        animal.doGrowl();
        animal = Animal.create(Cow.class);
        animal.doGrowl();
    }
}

final class Animal
{
    private Growl growl = null;

    private Animal()
    {
    }

    public void doGrowl()
    {
        growl.exec();
    }

    public abstract class Growl
    {
        public abstract void exec();

        public final void initialize()
        {
            if (growl != null)
            {
                throw new IllegalStateException("Already initialized.");
            }
            growl = this;
        }
    }

    public abstract static class Factory
    {
        public Factory(FactoryInitializer initializer)
        {
            initializer.validate();
        }

        public abstract void attachGrowl(Animal a);
    }

    public static final class FactoryInitializer
    {
        private boolean isValid = true;

        private FactoryInitializer()
        {
        }

        public void validate()
        {
            if (isValid)
            {
                isValid = false;
            }
            else
            {
                throw new IllegalStateException("FactoryInitializer is not valid.");
            }
        }
    }

    public static Animal create(Class<? extends Factory> factoryClass)
    {
        try
        {
            Constructor constructor = factoryClass.getConstructor(new Class[]{FactoryInitializer.class});
            Factory factory = (Factory) constructor .newInstance(new Object[]{new FactoryInitializer()});
            Animal animal = new Animal();
            factory.attachGrowl(animal);
            if (animal.growl == null)
            {
                throw new IllegalStateException("Animal factory did not initialize Growl.");
            }
            return animal;
        }
        catch (Exception e)
        {
            return null;
        }
    }
}

class Lion extends Animal.Factory
{
    public Lion(Animal.FactoryInitializer initializer)
    {
        super(initializer);
    }

    public void attachGrowl(Animal a)
    {
        a.new Growl()
        {
            public void exec()
            {
                System.out.println("rarrrrrr");
            }
        }.initialize();
    }
}

class Cow extends Animal.Factory
{
    public Cow(Animal.FactoryInitializer initializer)
    {
        super(initializer);
    }

    public void attachGrowl(Animal a)
    {
        a.new Growl()
        {
            public void exec()
            {
                System.out.println("mmooooo");
            }
        }.initialize();
    }
}
+2  A: 

What exactly is the motivation? The biggest issue I see is that it is non-intuitive for Lion to be an AnimalFactory instead of an Animal (that could be addressed with naming though).

TofuBeer
Basically I don't want the factories themselves to be used to do anything but attach a growl to an animal. And I don't want anyone to be using any sub-type of Animal. I'd like to freedom to use any animal factory I want, maybe just treating the Animal.class like a hint one day.
DW
oops... by "Animal.class" I meant Animal.Factory.class... what's passed to create(Class<? extends Factory> factoryClass)
DW
+9  A: 

Confused? Why not have Animal have a public constructor that takes a Growl? It shouldn't have to worry about how it was created.

Tom Hawtin - tackline
I don't want Growl to be able to be used directly.
DW
Why not? If you want to limit construction to a limited set of classes, make the constructor default access ("package private").
Tom Hawtin - tackline
But I want Growl to be implemented freely in any package.
DW
You want Growl to be extendable by anoyone, but one possible to use it from Animal. Doesn't make a great deal sf sense.
Tom Hawtin - tackline
+3  A: 

I've been trying to create a factory (in Java) that prohibits subclassing of the factory product and prevents the concrete factories from being used by anyone except the abstract factory. What do you think of this...

What you have created is a class that prohibits subclassing, not a factory that prevents subclassing of the factory product. Although subtle, that is an important difference.

If this is for homework, then I guess the reason for the question is a moot point, but under normal circumstances I would be very suspicious of the reason for doing something like this. What problem would you trying to solve? That is the purpose of code, after all.

Brad Barker
I guess essentially I'm trying to create a class with a virtual private method. And when classes implement this virtual private method they become final.
DW
Also, I am trying to ensure that no subtypes of the class with the virtual private are exposed.
DW
And no, I'm not a student, this is just a problem that's bugged me for a while and I had some down time at work today.
DW
No sane person would assign this as homework :-)
TofuBeer
If you want a class to be final, you writh final just before class...
Tom Hawtin - tackline
A: 

Not sure why you need this... but anyways

You can put the factory and the product's classes in the same package. Then, change product's classes to be package protected. Voila.

Antonio