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

阿图尔

ExecutorService和Service是接口,因此只有抽象方法,这意味着它们的方法未实现。那么,我们如何可以调用,例如future.get()es.submit()es.shutdown()方法的接口类型的参考?例如,为什么我们可以执行以下操作?

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

这是一个更具体的示例:

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();
    }
}
约书亚·泰勒(Joshua Taylor)

这个问题有些反对,因为从某种意义上说这是基本的,但我认为这实际上很有趣。毕竟,像Executors您的示例中所示的工厂类可以指定它返回Executors。但是,正如你所指出的,这只是一个接口,你真正需要的东西,一个实例工具 Executor,如果你要能够调用这些方法。工厂为什么不必告诉我们退货的实际类型?

如果您以前从未看过此内容,可能不清楚如何执行此操作。要记住的重要一点是,如果您有一个实现接口的类,则声明为返回接口类型的方法可以返回该类的实例。也就是说,您可以执行以下操作:

interface Foo { /* ... */ }

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

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

makeFoo声明返回a Foo,但是Foo是一个接口;您实际上无法获得它的实例。您只能拥有实现 的类的实例FooBar确实实现Foo,因此您可以返回的实例Bar

之所以能够这样做,是因为当需要在对象上调用方法时,该方法的实现是在我们引用的实际对象中找到的。查找方法的方式实际上有点复杂。不过,从概念上讲,您可能会这样想:如果您告诉我您是a Foo,那么我可以要求您运行在中声明的任何方法Foo,但是可以完全确定对该方法执行的操作。我只能使用您的Foo类型来确定我可以要求您执行的方法。这非常重要,这就是为什么我们可以在子类中重写方法的原因。这些称为虚拟方法如此重要的原因之一是,它使我们能够使用接口,在其中我们可以显示有关实现的最少信息(我们可以选择说“我实现Foo,但这就是我要告诉你的所有信息”),但仍然遵守合同(即,我保证可以实际实现中声明的所有方法Foo)。

以下示例更深入,并捕获了您所看到的更多工厂模式Executors

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

输出量

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何使用静态工厂方法创建抽象类?

来自分类Dev

如何创建返回不同接口类型和抽象类的通用工厂

来自分类Dev

如何混合静态类工厂方法和实例方法

来自分类Dev

接口,抽象类和抽象类的方法

来自分类Dev

包含工厂方法的抽象超类实现如何访问?

来自分类Dev

我可以在抽象类中创建静态工厂方法吗?

来自分类Dev

抽象类和接口

来自分类Dev

抽象类中的方法返回实现它的类的实例

来自分类Dev

返回通用实例的工厂方法

来自分类Dev

如何在抽象类和接口之间进行选择

来自分类Dev

Java实例vs抽象类和方法

来自分类Dev

如何创建使用guice工厂辅助注入创建并从抽象类扩展的类的实例?

来自分类Dev

Ruby类,子类和工厂方法

来自分类Dev

在抽象类和接口之间选择

来自分类Dev

Java-抽象类和接口

来自分类Dev

接口,抽象类和实现

来自分类Dev

使用接口和抽象类

来自分类Dev

接口与抽象类的方法为空

来自分类Dev

与抽象类的接口

来自分类Dev

普通接口类和仅具有抽象方法的抽象类之间是否有区别?

来自分类Dev

我似乎不了解工厂方法和抽象工厂方法之间的基本区别。

来自分类Dev

基类的工厂方法实例化派生类

来自分类Dev

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

来自分类Dev

如何指定抽象类方法的返回类型

来自分类Dev

如何指定抽象类方法的返回类型

来自分类Dev

如何创建抽象类的实例?

来自分类Dev

仅包含抽象方法和接口的抽象类-应该使用哪个?

来自分类Dev

具有所有方法抽象和接口的抽象类之间的区别?

来自分类Dev

c#如何返回在工厂方法中指定泛型类的类