簡體   English   中英

工廠方法如何返回接口和抽象類的實例?

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

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這樣的工廠類可以指定它返回Executor 但是,正如您所指出的那樣,這只是一個接口,如果您能夠調用這些方法,那么您實際上需要一個實現 Executor的實例。 工廠為什么不必告訴我們退貨的實際類型?

如果您以前沒有看過這個,可能不清楚如何做這樣的事情。 需要記住的重要一點是,如果您有一個實現接口的類,那么聲明為返回接口類型的方法可以返回該類的實例。 也就是說,你可以這樣做:

interface Foo { /* ... */ }

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

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

makeFoo被聲明為返回Foo ,但是Foo是一個接口; 您實際上無法獲得它的實例。 您只能擁有實現 Foo的類的實例。 Bar確實實現了Foo ,因此您可以返回Bar的實例。

我們可以這樣做的原因是,當需要在對象上調用方法時,該方法的實現可以在我們引用的實際對象中找到。 查找方法的方式實際上有點復雜。 但是從概念上講,您可能會這樣想:如果您告訴我您是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...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM