在Java中将枚举类型工厂设计为内部枚举类型

6

我尝试使用内部Enum实现了一个Enum样式的工厂模式,但它并没有起作用。 是否有解决方案,而不必将内部Enum分离成新文件? 换句话说,内部Enum样式的工厂模式是否可行?

以下是代码。

public class SampleParent {

    private class InnerChild { }
    private class InnerChildA extends InnerChild { }
    private class InnerChildB extends InnerChild { }
    private class InnerChildC extends InnerChild { }

    enum InnerChildEnum {
        CHILD_A {
            @Override
                public InnerChild getInstance() {
                    return new InnerChildA();  // compile error
                }
        },
        CHILD_B {
            @Override
                public InnerChild getInstance() {
                    return new SampleParent.InnerChildB();  // compile error
                }
        },
        CHILD_C {
            @Override
                public InnerChild getInstance() {
                    return SampleParent.new InnerChildC();  // compile error
                }
        },
        ;

        public abstract InnerChild getInstance();
    }

    private static class InnerChildFactoryEnumStyled {
        public static InnerChild getInnerChild(InnerChildEnum child) {
            return child.getInstance();
        }
    }


    public static void main(String[] args) {

        // I want to write this way
        InnerChild child = InnerChildFactoryEnumStyled.getInnerChild(InnerChildEnum.CHILD_A);
    }
}

编译错误信息如下:
$ javac SampleParent.java 
SampleParent.java:12: error: non-static variable this cannot be referenced from a static context
                return new InnerChildA();
                       ^
SampleParent.java:18: error: non-static variable this cannot be referenced from a static context
                return new SampleParent.InnerChildB();
                       ^
SampleParent.java:24: error: cannot find symbol
                return SampleParent.new InnerChildC();
                       ^
  symbol: variable SampleParent
3 errors

你可以将 InnerChildXX 类设置为静态的。根据你的示例,这不会有问题。 - assylias
答案在这里:https://dev59.com/u3RB5IYBdhLWcg3wUFrB - Markus Benko
谢谢,正如我之前提到的,不幸的是,实际的内部类是AsyncTask的子类,无法是静态的。 - forte916
3个回答

5

你的内部类不是静态的,因此必须引用封闭类SampleParent的实例。将你的类声明更改为:

private static class InnerChild { }
private static class InnerChildA extends InnerChild { }
private static class InnerChildB extends InnerChild { }
private static class InnerChildC extends InnerChild { }

在枚举中,您可以使用return new InnerChildA();等语句。


我看到你在我之前发布了答案,所以我删除了我的帖子。 - fps
谢谢你提供的解决方案。修改静态变量确实是有道理的。但不幸的是,实际的内部类是 AsyncTask 的子类,该子类具有非静态成员。你的答案非常有帮助。 - forte916

3
要实例化非静态内部类(InnerChildA、InnerChildB等),需要使用封闭类型SampleParent的实例来限定实例化。您需要这样做:new ExternalClass().new InternalClass()。
在您的情况下,您可以在InnerChildEnum枚举中声明并实例化一个静态SampleParent实例,并在每个enum值声明的getInstance()方法中重复使用它。
private class InnerChild {
}

private class InnerChildA extends InnerChild {
}

private class InnerChildB extends InnerChild {
}

private class InnerChildC extends InnerChild {
}

enum InnerChildEnum {

    CHILD_A {
        @Override
        public InnerChild getInstance() {
            return sampleParent.new InnerChildA();
        }
    },
    CHILD_B {
        @Override
        public InnerChild getInstance() {

            return sampleParent.new InnerChildB(); // compile error
        }
    },
    CHILD_C {
        @Override
        public InnerChild getInstance() {
            return sampleParent.new InnerChildC();
        }
    };

    private static SampleParent sampleParent = new SampleParent();

    public abstract InnerChild getInstance();
}

谢谢您的帖子,我会尝试并报告结果。 - forte916
第一个问题已经解决了。不幸的是,我又遇到了另一个问题。在枚举中创建的实例和原始实例是不同的对象。因此,如果SampleParent有非实例成员,则创建的实例无法引用原始实例的成员。但这是第二个问题。我正在尝试解决。 - forte916
我认为你会说“如果SampleParent有实例成员...”。为了解决你的问题,你应该在这两个类之间共享这个实例,甚至可能确保你没有超过一个SampleParent实例。简单的方法(共享实例):将private static SampleParent sampleParent = new SampleParent();替换为public static SampleParent sampleParent = new SampleParent();现在你可以在任何地方引用相同的对象,因为它是公共的。 - davidxxx
关于如何在运行时只有一个实例的方法,您可以使用经典的单例模式或依赖注入。 - davidxxx

1

改进代码在这里,以备不时之需。

public class SampleParent {

    private String foo = "foo";

    private abstract class InnerChild {
        public abstract void doSomething();
    }
    private class InnerChildA extends InnerChild {
        public void doSomething() {
            System.out.println(foo);  // refer sampleParent.foo, not original's foo
        }
    }
    private class InnerChildB extends InnerChild {
        public void doSomething() {
            System.out.println(foo);  // refer sampleParent.foo, not original's foo
        }
    }
    private class InnerChildC extends InnerChild {
        public void doSomething() {
            System.out.println(outer().foo);  // refer sampleParent.foo, not original's foo
        }
    }

    enum InnerChildEnum {
        CHILD_A {
            @Override
            public InnerChild getInstance() {
                return sampleParent.new InnerChildA();
            }
        },
        CHILD_B {
            @Override
            public InnerChild getInstance() {
                return sampleParent.new InnerChildB();
            }
        },
        CHILD_C {
            @Override
            public InnerChild getInstance() {
                return sampleParent.new InnerChildC();
            }
        },
        ;

        private static SampleParent sampleParent = new SampleParent();
        public abstract InnerChild getInstance();
    }

    private static class InnerChildFactoryEnumStyled {
        public static InnerChild getInnerChild(InnerChildEnum child) {
            return child.getInstance();
        }
    }


    public static void main(String[] args) {
        System.out.println("Hello World.");

        // I want to write this way
        InnerChild childA = InnerChildFactoryEnumStyled.getInnerChild(InnerChildEnum.CHILD_A);
        childA.doSomething();

        InnerChild childB = InnerChildFactoryEnumStyled.getInnerChild(InnerChildEnum.CHILD_B);
        childB.doSomething();

        InnerChild childC = InnerChildFactoryEnumStyled.getInnerChild(InnerChildEnum.CHILD_C);
        childC.doSomething();
    }

    public SampleParent outer() {
        return SampleParent.this;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接