简体   繁体   English

工厂方法如何返回接口和抽象类的实例?

[英]How can factory methods return instances of interfaces and abstract classes?

ExecutorService and Service are interfaces and so only have abstract methods, which means that their methods are not implemented. ExecutorService和Service是接口,因此只有抽象方法,这意味着它们的方法没有实现。 How then can we call, eg, future.get() , es.submit() , and es.shutdown() methods on references of the interface type? 那么我们怎么能在接口类型的引用上调用例如future.get()es.submit()es.shutdown()方法呢? Eg, why can we do the following? 例如,为什么我们可以执行以下操作?

Future f = ...
f.get();

Here's a more concrete example: 这是一个更具体的例子:

import java.util.concurrent.*;
class Factorial implements Callable<Long> {
    long n;
    public Factorial(long n) {
        this.n = n;
    }

    public Long call() throws Exception {
        if (n <= 0) {
            throw new Exception("for finding factorial, N should be > 0");
        }
        long fact = 1;
        for(long longVal = 1; longVal <= n; longVal++) {
            fact *= longVal;
        }
        return fact;
    }
}

class CallableTest {
    public static void main(String []args) throws Exception {
        long N = 20;

        Callable<Long> task = new Factorial(N);
        ExecutorService es = Executors.newSingleThreadExecutor();
        Future<Long> future = es.submit(task);

        System.out.printf("factorial of %d is %d", N, future.get());
        es.shutdown();
    }
}

This question got some downvotes because in one sense it's sort of basic, but I think it's actually sort of interesting. 这个问题得到了一些贬低,因为从某种意义上来说它是基本的,但我认为它实际上有点有趣。 After all, a factory class like Executors in your example, can specify that it returns Executor s. 毕竟,在您的示例中,像Executors这样的工厂类可以指定它返回Executor But, as you point out, that's just an interface, and you'd actually need an instance of something that implements Executor if you're going to be able to call those methods. 但是,正如您所指出的那样,这只是一个接口,如果您能够调用这些方法,那么您实际上需要一个实现 Executor的实例。 Why doesn't the factory have to tell us the actual type of thing that's being returned? 工厂为什么不必告诉我们退货的实际类型?

If you haven't seen this before, it might not be clear how you could do such a thing. 如果您以前没有看过这个,可能不清楚如何做这样的事情。 The important thing to remember is that if you have a class that implements an interface, then a method declared to return the interface type can return an instance of the class. 需要记住的重要一点是,如果您有一个实现接口的类,那么声明为返回接口类型的方法可以返回该类的实例。 That is, you can do: 也就是说,你可以这样做:

interface Foo { /* ... */ }

class Bar implements Foo { /* ... */ }

class Factory {
  Foo makeFoo() { 
    return new Bar( /*... */ );
  }
}

makeFoo is declared to return a Foo , but Foo is an interface; makeFoo被声明为返回Foo ,但是Foo是一个接口; you can't actually have instance of it. 您实际上无法获得它的实例。 You can only have instance of classes that implement Foo . 您只能拥有实现 Foo的类的实例。 Bar does implement Foo , so you can return an instance of Bar . Bar确实实现了Foo ,因此您可以返回Bar的实例。

The reason that we can do this is because when it comes time to invoke a method on an object, the implementation of the method is found in the actual object that we have a reference to. 我们可以这样做的原因是,当需要在对象上调用方法时,该方法的实现可以在我们引用的实际对象中找到。 The way that methods are looked up is actually a bit complicated. 查找方法的方式实际上有点复杂。 Conceptually though, you might think of it like this: if you tell me that you're a Foo , then I can ask you to run any of the methods that are declared in Foo , but you get to decide exactly what you do for that method. 但是从概念上讲,您可能会这样想:如果您告诉我您是Foo ,那么我可以要求您运行Foo中声明的任何方法,但是必须完全确定要为此做些什么。方法。 I only get to use your Foo type in determining what methods I can ask you to execute. 我只能使用您的Foo类型来确定我可以要求您执行的方法。 This is very important, and is why we can override methods in subclasses. 这非常重要,这就是为什么我们可以在子类中重写方法的原因。 These are called virtual methods . 这些被称为虚拟方法 One of the reasons this is so important is that it enables us to use interfaces where we can reveal a minimal amount of information about our implementation (we can choose to say "I implement Foo , but that's all I'm telling you about myself), but still abide by a contract (ie, I'm guaranteed to actually implement all the methods declared in Foo ). 如此重要的原因之一是,它使我们能够使用接口,在其中我们可以揭示有关实现的最少信息(我们可以选择说“我实现Foo ,但这就是我要告诉你的全部信息)” ,但仍然遵守合同(即,我保证实际实现在Foo声明的所有方法)。

The following example is a bit more in depth, and captures a bit more of the factory pattern that you see with Executors . 下面的示例更深入一些,并捕获了您使用Executors看到的工厂模式的更多信息。

Code

public class InterfacesExample {

    /**
     * An interface with one method.
     */
    interface Frobber {
        /**
         * Frob the object.
         * @param object the object
         */
        void frob( Object object );
    }

    /**
     * A factory class with one method for creating printing frobber.
     */
    public static class Frobbers {
        /**
         * Returns a Frobber whose {@link Frobber#frob(Object)} method
         * prints its argument
         * @return a printing Frobber
         */
        public static Frobber newPrintingFrobber() {
            // This returns an instance of an anonymous class
            // that implements the Frobber interface.  It has 
            // to provide an implementation of frob(Object),
            // though.
            return new Frobber() {
                @Override
                public void frob( final Object object ) {
                    System.out.println( "Frobbing "+object+"..." );
                }
            };
        }

        /**
         * Returns a Frobber whose {@link Frobber#frob(Object)} method
         * prints the prefix and its argument
         * @param prefix an object
         * @return a prefixing printing Frobber
         */
        public static Frobber newPrefixingPrintingFrobber( final Object prefix ) {
            return new PrefixingPrintingFrobber( prefix );
        }

        /**
         * A private, but not anonymous class.  Instances shouldn't be
         * made with its constructor, but rather through the factory 
         * method {@link Frobbers#newPrefixingPrintingFrobber(Object)}. 
         */
        private static class PrefixingPrintingFrobber implements Frobber {
            final Object prefix;

            public PrefixingPrintingFrobber( Object prefix ) { 
                this.prefix = prefix;
            }

            @Override
            public void frob( final Object object ) {
                System.out.println( "Frobbing "+prefix+":"+object+"..." );
            } 

        }
    }

    /**
     * Create some frobbers with the factory and test them out.
     */
    public static void main( final String[] args ) {
        final Frobber f1 = Frobbers.newPrintingFrobber();
        f1.frob( 42 );

        final Frobber f2 = Frobbers.newPrefixingPrintingFrobber( "boing" );
        f2.frob( 36 );
    }
}

Output 产量

Frobbing 42...
Frobbing boing:36...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM