如何使构造函数仅可用于工厂类?

时间:2022-09-11 20:59:58

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.

假设我有一个名为CFactory的Shoe(CShoe)对象工厂类。 CFactory是一个单例类,使用简单的hashmap创建和存储所有instanciated鞋。然后通过静态方法访问它以使用创建的对象。

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)

有没有办法强制CShoe的构造函数,以便它只能由工厂调用? (换句话说,确保鞋子的制作只能由鞋厂单身人士班而不是其他班级完成)

6 个解决方案

#1


You could make Shoe an inner class of ShoeFactory:

你可以让Shoe成为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();
        }
    }
}

#2


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

你可以给CShoe构造函数包访问,并将CShoe和CFactory放在同一个包中。

#3


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.

由于您想要将每个对象添加到地图中,您也可以将此逻辑移动到CShoe构造函数 - 该对象将自行添加。

#4


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.

首先,如果保留所有创建的实例,则称为泄漏。我将继续假设您的意思是非强引用,有界或某些此类缓存,并且Shoe是不可变的。

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;
    }
    ...
}

#5


You could perhaps pass the factory object into the constructor?

您可以将工厂对象传递给构造函数?

public CShoe(CFactory factory)
{
    if (factory == null ||
          !factory.isValid()) // or whatever
    {
        throw new IllegalArgumentException();
    }
}

#6


Couldn't you just pass the caller instance as argument of a static member of shoe and in there do a check like "isInstanceOf" which calls the constructor if true?

难道你不能只将调用者实例作为鞋子的静态成员的参数传递,并在那里做一个像“isInstanceOf”这样的检查,如果为真,它会调用构造函数吗?

#1


You could make Shoe an inner class of ShoeFactory:

你可以让Shoe成为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();
        }
    }
}

#2


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

你可以给CShoe构造函数包访问,并将CShoe和CFactory放在同一个包中。

#3


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.

由于您想要将每个对象添加到地图中,您也可以将此逻辑移动到CShoe构造函数 - 该对象将自行添加。

#4


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.

首先,如果保留所有创建的实例,则称为泄漏。我将继续假设您的意思是非强引用,有界或某些此类缓存,并且Shoe是不可变的。

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;
    }
    ...
}

#5


You could perhaps pass the factory object into the constructor?

您可以将工厂对象传递给构造函数?

public CShoe(CFactory factory)
{
    if (factory == null ||
          !factory.isValid()) // or whatever
    {
        throw new IllegalArgumentException();
    }
}

#6


Couldn't you just pass the caller instance as argument of a static member of shoe and in there do a check like "isInstanceOf" which calls the constructor if true?

难道你不能只将调用者实例作为鞋子的静态成员的参数传递,并在那里做一个像“isInstanceOf”这样的检查,如果为真,它会调用构造函数吗?