接口类java中的静态工厂方法

时间:2013-12-13 10:08:36

标签: java static-factory

我正在阅读有效的java 教科书。第一项是关于使用静态工厂方法而不是公共构造函数。我怀疑的是,如果我指定Interface我如何在Interface中指定静态工厂方法?因为java不支持interface内的静态方法。教科书指定了如何创建包含公共静态工厂方法的不可实例化的类。但是这些方法如何访问实现类的私有构造函数呢?

教科书说如果要定义Interface Type,请创建一个不可实例化的类Types,并在该类中包含静态工厂方法。但是Types类中定义的方法如何访问Interface Type的具体实现的私有构造函数

编辑: - 以下句子引自教科书。请解释一下它的含义

“接口不能有静态方法,因此按照惯例,名为 Type 的接口的静态工厂方法放在名为 Types 的不可实例化的类(Item 4)中“

编辑: - 取自Effective Java By Joshua Bloch: Item1 - Static Factory Method

     public interface Foo{ //interface without plural 's' (question 1)
     public void bar();
 }
 public abstract class Foos(){ // abstract factory with plural 's' (question 1)
    public static Foo createFoo(){
        return new MyFoo();
    }
    private class MyFoo implements Foo{ // a non visible implementation (question 2)
       public void bar(){}
    }
 }

我的问题是静态方法createFoo()如何调用MyFoo的私有构造函数

5 个答案:

答案 0 :(得分:5)

这个问题在JAVA 8中得到解决。现在接口可以有静态方法。更多详情: - http://www.techempower.com/blog/2013/03/26/everything-about-java-8/

答案 1 :(得分:3)

您可以将工厂定义为返回接口,但在内部它会创建一个具体的类。

例如:

public Interface I { }

private class Impl implements I {
}

I buildI() {
    return new Impl();
}

诀窍是创建包私有(或者即使它们是私有内部类)构造函数的实现,然后只有工厂可以构建它们。

这种方法的强大之处在于,工厂可以根据要求构建适当的实现,并且所有实现都对用户不可见。例如,当您使用工厂创建EnumSet时,有多个内部实现,具体取决于Enum中正在构建EnumSet的条目数。一个超长版本,使用长Enums的位域,少于64个条目,对于更长的枚举,速度较慢。

要指定工厂的界面,您只需:

public interface Factory {
   I buildI();
}

现在,人们可以通过setFactory(new FactoryImpl());给您打电话,然后您可以调用factory.buildI(),然后他们的代码会返回具体的实现。

您可以更进一步,使用泛型:

public interface GenericFactory<T> {
    T buildInstance();
}

然后你的setFactory变为:

public void setFactory(GenericFactory<I> factory);

要创建工厂,他们会这样做:

public class FactoryImpl implements GenericFactory<I> {
     @override
     I buildInstance() {
        return new impl();
     }
}

但现在你可以使用同一个工厂类来完成任何需要工厂的工作,只需更改泛型要求。

它可以调用私有构造函数的原因非常简单 - 它在同一个类中声明!

在一个Java文件中,您可以使用私有构造函数创建类。然后在类中定义静态方法,即使它是静态的,它仍然具有访问构造函数所需的特权。

如果工厂和实现位于不同的类中,那么它们将被放置在同一个包中,并且该方法将包设为私有而不是私有。

答案 2 :(得分:0)

它讨论了在实现中通过静态工厂方法创建对象而不是接口

public Interface MyInterface {
    public void myFunction();
}

public class MyClass implements MyInterface {

    // constructor is made private
    private MyClass() {}

    // Use this to create object instead use static factory
    public static MyClass getInstance() {
        return new MyClass();
    }

    public void myFunction(){
      // your implementation
    } 
}

上一篇文章还讨论了静态工厂方法.. What are static factory methods?

除了这本书之外,我还发现下面提到的链接很好 http://www.javacodegeeks.com/2013/01/static-factory-methods-vs-traditional-constructors.html

答案 3 :(得分:0)

您无法在接口中定义工厂方法,但也不能在接口中使用构造函数:接口无法实例化。关键是在实现接口的类中使用工厂方法而不是构造函数,而不是在接口本身。

答案 4 :(得分:0)

考虑这一点的一种方法是考虑封装。考虑下面的Java 9+代码:

public interface Engine {

    void start();

    static Engine getEngine(String type) {
        switch (type) {
            case "combustion":
                return new CombustionEngine();
            case "electric":
                return new ElectricEngine();
            default:
                throw new IllegalArgumentException("Unknown engine type : " + type);
        }
    }
}

class CombustionEngine implements Engine {

    CombustionEngine() {
    }

    @Override
    public void start() {
        // injecting fuel and igniting it to create combustion...
    }
}

class ElectricEngine implements Engine {

    ElectricEngine() {
    }

    @Override
    public void start() {
        // electric current from battery flowing through coil in magnetic field...
    }
}

请注意,实现中的构造函数是程序包私有的,因此来自其他程序包的调用者无法直接实例化实现,而应使用factory方法。

界面中具有工厂方法

  • 不需要专用的EngineFactory类(Factory方法设计模式的传统实现)
  • 提醒程序要界面,而不是实现

如果需要,还有一种方法可以将实现实例创建为单例,从而改善内存占用量:

public interface Engine {

    enum EngineType {

        COMBUSTION,
        ELECTRIC;

        private static EnumMap<EngineType, Engine> MAP = new EnumMap<>(EngineType.class);

        static {
            MAP.put(COMBUSTION, new CombustionEngine());
            MAP.put(ELECTRIC, new ElectricEngine());
        }
    }

    void start();

    static Engine getEngine(EngineType type) {
        return EngineType.MAP.get(type);
    }

}