Java面向对象编程:这真的可能吗?

6

我想要隐藏一个我不拥有的类的实现细节。我计划通过扩展该类并实现自己的接口来实现此目的。下面是需要创建的类的示例:

QueueInfo info = admin.getQueue(queueName);

QueueInfo是我不拥有的类。要获取这个对象的实例,我必须使用管理员对象来获取它。我想通过一个名为IQueueInfo的接口来隐藏此实现。IQueueInfo将只提供消费者从QueueInfo所需的访问权限。因此,为了获取这个QueueInfo,我想通过自己的对象EMSQueueInfo来工作。这就是我设想设置它的方式:

public class EMSQueueInfo extends QueueInfo implements IQueueInfo {
    //...
}

这让我的消费者能够通过IQueueInfo接口工作,同时也允许底层EMSQueueInfo访问QueueInfo的全部内容。我的问题在于如何获取一个“活”的QueueInfo实例。如果要获取一个常规的QueueInfo实例,我只需要执行以下操作:

QueueInfo info = new QueueInfo(queueName);

这个实例不是由管理员对象创建的,因此它不是“活动的”。所以,做这个:

public class EMSQueueInfo extends QueueInfo implements IQueueInfo {

    public EMSQueueInfo(String queueName){
        super(queueName);
    }

}

这个方法不能返回一个“实时”对象。我希望能够像下面这样做:

public class EMSQueueInfo extends QueueInfo implements IQueueInfo {

    public EMSQueueInfo(String queueName, Admin admin){
        super = admin.getQueue(queueName);
    }

}

但这是不可能的。

我看到的唯一解决方案是从我的EMSQueueInfo类中移除extends,并仅仅通过私有变量来包装对象,以获取对所有方法的访问:

public class EMSQueueInfo extends QueueInfo implements IQueueInfo {

    private QueueInfo _queueInfo

    public EMSQueueInfo(String queueName, Admin admin){
        _queueInfo = admin.getQueue(queueName);
    }

    public int getMessagesOnQueue() {
        return _queueInfo.getMessagesOnQueue();
    }

}

那个解决方案确实可行,但我有点讨厌它。有没有人能想到更好的方法?我是不是在试图破坏OO并滥用它?再次说明,我之所以这样做是因为我希望消费者能够使用IQueueInfo,在未来,IQueueInfo可以用于访问QueueInfo的JMS实现或QueueInfo的MSMQ实现。任何帮助都将是惊人的!


我会对你试图隐藏的类进行扩展保持警惕。我不认为组合有什么问题。 - Dave Newton
Google工厂方法 - Bohemian
你已经描述了“适配器”模式:你包装某些东西,只允许访问其中的某些部分。所以你希望queueInfo被隐藏起来。否则,人们将能够访问它上面的所有字段,而不仅仅是你想让他们访问的那些字段。 - David Lavender
我可以创建一个静态的Admin实例,但我不认为这会解决我的问题。 - Tyler Wright
为什么你讨厌你的解决方案?在我看来,它看起来是正确的答案。 - Aaron Kurtzhals
你可以为接口创建一个动态代理类。 - Joop Eggen
2个回答

6
我相信你正在使用的解决方案是一个好的解决方案,你所说的讨厌并不会破坏面向对象编程或者滥用它。
你正在做的是一个众所周知的模式,叫做适配器模式(对象适配器模式)。在你的类中唯一不需要的是扩展QueueInfo。

你的答案也是正确的。我之所以选择了Duncan的答案而不是你的,是因为他还提供了一个很好的代码示例。不过还是谢谢你的回答! - Tyler Wright

5
你提出的建议似乎非常合理 - 这被称为适配器模式(感谢Martinsos)。
如果你能以某种方式隐藏你的类中的 Admin 对象会更好。例如:
public class EMSQueueInfo implements QueueInfoProvider {

    private static Admin admin = new Admin();
    private QueueInfo queueInfo

    public EMSQueueInfo(String queueName){
        queueInfo = admin.getQueue(queueName);
    }

    public int getMessagesOnQueue() {
        return queueInfo.getMessagesOnQueue();
    }

}

我试图给你的界面取一个更“Java”的名称。后缀“I”非常.NET。不需要扩展原始类。
实现起来可能会感到痛苦,因为您必须费力地将QueueInfo中的“有趣的方法”复制到QueueInfoProvider中,但最终这种痛苦是值得的。
这种方法使您的应用程序与您无直接控制的API解耦。在这个意义上,它类似于Facade pattern

1
抱歉,我来自.NET。再次强调,我不想包装整个类。我要避免上述方法。getMessagesOnQueue已经是QueueInfo的一部分了。 - Tyler Wright
没问题。有了这个设计,你可以选择要包装哪些方法。如果只有一个,那也没问题。 - Duncan Jones
我认为你是正确的。只是当我觉得通过扩展类来实现这个功能是正确的方式时,不得不重写所有内容让我感到有些不舒服。 - Tyler Wright
你所做的是最好的。你已经将你的应用程序与一个你无法控制的API解耦。这就是外观模式背后的原则,它也类似于你在这里所做的。 - Duncan Jones
还是希望我能说super = admin.getQueue(queueName)。那会很酷!但你是正确的。谢谢!!! - Tyler Wright
@TylerWright 你不是在重写,而是在委派。大多数IDE都会自动完成这个过程,或者你可以将一些东西放入构建过程中,或者使用Lombok等工具。 - Dave Newton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接