【问题标题】:Inheritance and composition of the same class in JavaJava中同一个类的继承与组合
【发布时间】:2017-11-20 15:04:10
【问题描述】:

我在 github 上找到了以下代码:

public class DummySSLSocketFactory extends SSLSocketFactory {

    private static final Logger LOG = LoggerFactory.getLogger(DummySSLSocketFactory.class);
    private SSLSocketFactory factory;

    public DummySSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManager[] trustManagers = new TrustManager[] {new DummyTrustManager()};
            sslContext.init(null, trustManagers, new java.security.SecureRandom());
            factory = sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeCamelException("Error creating DummySSLSocketFactory: " + e.getMessage(), e);
        }
    }

    /**
     * Must provide this getDefault operation for JavaMail to be able to use this factory.
     */
    public static SocketFactory getDefault() {
        LOG.warn("Camel is using DummySSLSocketFactory as SSLSocketFactory (only to be used for testing purpose)");
        return new DummySSLSocketFactory();
    }

    public String[] getDefaultCipherSuites() {
        return factory.getDefaultCipherSuites();
    }

    public String[] getSupportedCipherSuites() {
        return factory.getSupportedCipherSuites();
    }

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return factory.createSocket(socket, host, port, autoClose);
    }

    public Socket createSocket(String host, int port) throws IOException {
        return factory.createSocket(host, port);
    }

    public Socket createSocket(String host, int port, InetAddress localAddress, int localPort)
        throws IOException {
        return factory.createSocket(host, port, localAddress, localPort);
    }

    public Socket createSocket(InetAddress host, int port) throws IOException {
        return factory.createSocket(host, port);
    }

    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
        throws IOException {
        return factory.createSocket(address, port, localAddress, localPort);
    }

    public Socket createSocket() throws IOException {
        // must have this createSocket method
        return factory.createSocket();
    }

}

类似的实现被广泛用于不同的项目。 我试图弄清楚同时使用继承和组合的目的是什么。看起来只要有一个返回 sslContext.getSocketFactory(); 结果的工厂方法就足够了,因为它根本不扩展类。

【问题讨论】:

  • 也许他们不能只使用工厂方法,因为他们正在使用某种基于反射的框架,需要一个具有可访问构造函数的类,或者他们可能需要显式创建一个自定义子类SSLSocketFactory 出于某种原因。或者他们可能想为每个方法添加日志记录功能,但他们还没有完成类的实现。在这种特殊情况下很难确定。

标签: java inheritance composition sslcontext


【解决方案1】:

我不知道谁编写这段代码的确切意图是什么,但在这种类组织中很明显,使用组合和继承,DummySSLSocketFactory 可以使用受保护的方法 在 SSLSocketFactory 甚至上面的类中实现(使用 super)。
这是可能的,因为DummySSLSocketFactory 引用了它的父类SSLSocketFactory

 private SSLSocketFactory factory;

在 DummySSLSocketFactory 的构造函数中设置

factory = sslContext.getSocketFactory();

如果没有这个引用,您将能够使用 super 访问 SSLSocketLayer,但不能使用更高的类。

【讨论】:

  • 这听起来很合理。现在我看到了在一个类中结合组合和继承的好处,所以我会接受你的回答。
  • 你的意思不是很受保护吗?据我所知,无法访问继承类中的私有成员/方法。
  • 是的,你是对的,我会更正答案。我的意思是,通过组合,您可以直接指向上层类 SSLSocketFactory,以便在特定实现中使用某些方法,这可能在 Dummy 中被覆盖。关于会员,我错了,我看不出这样做有什么特别的收获。
【解决方案2】:

这是一种常见的模式(正如您所提到的)。

子类可以扩展类(或实现接口)以建立“is-a”关系。 在你的例子中, DummySSLSocketFactory 是一个SSLSocketFactory。 “is-a”关系允许多态性。

子类可能不希望完全覆盖(或在接口的情况下实现)方法, 所以它使用组合来获得已经覆盖了无趣但必需的方法的东西。 为达到这个, 子类会将对“无趣”(我在那里的术语)方法的调用转发给组合成员。 在您的示例中,原始类 SSLSocketFactory 提供了 DummySSLSocketFactory 类不感兴趣的东西的“默认”实现。

将调用转发到组合成员是代理模式的一种变体。它不是一个完整的代理,因为它改变了功能。

【讨论】:

  • 在这种情况下,我认为我们不需要组合。除了实现代理方法,我们可以跳过实现它们
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多