工厂方法如何返回接口和抽象类的实例? [英] How can factory methods return instances of interfaces and abstract classes?

查看:0
本文介绍了工厂方法如何返回接口和抽象类的实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

推荐答案

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

如果您以前没有见过这一点,可能不清楚您是如何做到这一点的。需要记住的重要一点是,如果您有一个实现接口的类,则声明为返回接口类型的方法也可以返回该类的实例。也就是说,您可以:

interface Foo { /* ... */ }

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

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

makeFoo被声明为返回Foo,但Foo是一个接口;您不能实际拥有它的实例。您只能拥有实现Foo的类的实例。Bar实现了Foo,所以您可以返回Bar的实例。

之所以可以这样做,是因为当调用对象上的方法时,该方法的实现可以在我们引用的实际对象中找到。查找方法的方式实际上有点复杂。不过,从概念上讲,您可能会这样想:如果您告诉我您是Foo,那么我可以要求您运行Foo中声明的任何方法,但将决定为该方法做什么。我只能使用您的Foo类型来确定我可以要求您执行哪些方法。这一点非常重要,这也是为什么我们可以重写子类中的方法。这些被称为virtual methods。这很重要的原因之一是,它使我们能够使用接口,在这些接口中,我们可以透露有关实现的最少量信息(我们可以选择说"我实现了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...

这篇关于工厂方法如何返回接口和抽象类的实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆