13

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

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

编辑:- 下面的句子是从教科书中引用的。请解释一下它的含义

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

编辑:- 取自Joshua Bloch 的 Effective Java: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

4

5 回答 5

7

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

例如:

public Interface I { }

private class Impl implements I {
}

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

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

这种方法的强大之处在于工厂可以根据需求构建适当的实现,而这一切对用户来说都是不可见的。例如,当您使用工厂创建时,有多个内部实现,具体取决于正在构建的条目EnumSet中有多少。一个超快的版本,在 long for 上使用位域,少于 64 个条目,一个较慢的版本,用于更长的枚举。EnumEnumSetEnums

要为工厂指定接口,您需要做的就是:

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 文件中,您可以使用私有构造函数创建类。然后在类中定义静态方法,即使它是静态的,它仍然具有访问构造函数所需的权限。

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

于 2013-12-13T10:10:14.697 回答
5

Java 8 最终允许接口拥有静态方法。

有关详细信息,请参阅TechEmpower 博客的存档副本。

于 2013-12-24T05:11:40.350 回答
3

考虑这一点的一种方法是考虑到包封装。考虑这个 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...
    }
}

请注意,实现中的构造函数是包私有的,因此来自不同包的调用者不能直接实例化实现,应该使用工厂方法。

在接口中有工厂方法

  • 不需要专门的EngineFactory类(工厂方法设计模式的传统实现)
  • 提醒程序接口,而不是实现

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

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

}
于 2020-06-12T10:45:16.110 回答
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
    } 
}

之前的一篇文章也谈到了静态工厂方法。什么是静态工厂方法?

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

于 2013-12-13T10:14:38.267 回答
0

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

于 2013-12-13T10:28:31.077 回答