`
wxl24life
  • 浏览: 293292 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ActiveMQ 源码学习 2:从 CommandTypes 谈常量接口反模式

阅读更多

在上一篇文章里,我写了在阅读 ActiveMQ 的一小段源码时碰到的两种设计模式:抽象工厂和策略模式。实际上 ActiveMQ 源码量很大,只要认真分析,你会找到很多设计模式的应用场景。其中,有一个模式非常典型,并且它在整个 ActiveMQ 的源码架构中扮演者非常重要的角色,它就是 GoF 设计模式中的:命令模式(Command Pattern)。Command 是 ActiveMQ broker 与 client 的主要通信方式,每个 Command 对象代表了一个待执行的动作。关于命令模式在 ActiveMQ 源码中的应用,我会在后面找个时间专门写一下。

 

这篇文章讨论另一个问题。它是我在开始分析 ActiveMQ 中 Command 实现时碰到的。起因是这样的,我发现了一种不常见的接口定义:

 

/**
 * Holds the command id constants used by the command objects.
 * 
 * Mark by wxl24life: 2013-08-15
 * Constant Interface Antipattern
 */
public interface CommandTypes {

    // /////////////////////////////////////////////////
    //
    // Info objects sent back and forth client/server when
    // setting up a client connection.
    //
    // /////////////////////////////////////////////////
    byte WIREFORMAT_INFO = 1;
    byte BROKER_INFO = 2;
    byte CONNECTION_INFO = 3;
    byte SESSION_INFO = 4;
    byte CONSUMER_INFO = 5;
    byte PRODUCER_INFO = 6;
    byte TRANSACTION_INFO = 7;
    byte DESTINATION_INFO = 8;
    byte REMOVE_SUBSCRIPTION_INFO = 9;

    // ...Other constants definement ignored
}

 

这种写法我是第一次碰到:接口中没有包含任何的方法,只是定义了一些常量属性。抱着这种疑惑,按照惯例自然首先要求助的便是 google,简单的两个关键字可以锁定到 SO 上的这个问答:What is the use of interface constants -- 小提示:在 google 搜索结果里,StackOverFlow 上的问答链接应该始终作为不二的选择

 

得票数最高的回答里获取到的最有价值信息是:这种用法称为常量接口,它是一种典型的 Java 反模式,并且在 Joshua Bloch 的 Effective Java 里有单独的条目详细描述了这个问题。所谓的反模式是指,不建议使用的方法。结合前面碰到的问题,CommandTypes 不应该或者至少是不建议被定义成那样的常量接口。换句话说,再优秀的开源代码中也会有一些不那么“优秀”的用法。真的是这样么?看下面的分析。

 

首先,接口中是可以定义属性的,在不带任何修饰符的情况下,默认是 static final 的。在接口中定义的属性可以在接口的实现类中直接访问,而不需要使用类名进行引用,也就是说,接口中的属性传递到了它的实现类的名字空间里去了。因此,在接口中已经定义了方法的前提下,偶尔定义少量的属性是可以接受的。但是,Java 同时允许常量接口的存在,所谓常量接口就是在接口中只定义属性而不包含方法,这显然违背了接口存在的初衷:接口为它的实现类提供了一种向外界暴露服务的方式。因而,当你定义常量接口的目的是为它的实现类访问常量属性提供便利的时候,就符合 Joshua Bloch 所说的 “常量接口是对接口的不良使用” 了。

 

在 Effective Java 第二版的条目19中描述了使用常量接口可能会产生的问题,以及它的替代用法。

 

  • 类在内部使用某些常量属于实现细节,实现常量接口会导致这样的实现细节泄漏到该类的导出API。
  • 如果非 final 类实现了常量接口,它的子类的名字空间也会被接口中的常量所污染。

通过一段代码来解释上面这两句话:

 

/**
 * @author wxl24life
 *
 */
public class AntiPatternConstantInterfaceImpl implements CommandTypes {
	public byte getActivemqQueue() {
		return ACTIVEMQ_QUEUE; // 常量接口带来的“便利”
	}
	
	public static void main(String[] args) {
		AntiPatternConstantInterfaceImpl antiPat = new AntiPatternConstantInterfaceImpl();
		byte a = antiPat.WIREFORMAT_INFO; // 产生的问题1:实现细节泄漏
		new AntiPatternConstantInterfaceImpl() {
			public void foo() {
				byte b = WIREFORMAT_INFO; // 产生的问题2:子类名字空间被“污染”
			}
		};
	}
}

 

 

当然,在 ActiveMQ 的源码里,CommandTypes 虽然被定义成常量接口,却没有任何类实现这个接口,常量接口在这里充当的角色是:定义一些公共的常量属性提供给其他类引用,相当于一个常量集合。这种用法严格上说不符合常量接口反模式的用法,但是使用接口定义一个常量集合仍然是不够合适的。

 

为此可以考虑另外的一些定义常量集合的方式,比如枚举类型(enum),或者定义一个不可实力化的工具类。

 

 

/**
 * @author wxl24life
 *
 */
public final class CommandTypesUtility {
	
	private CommandTypesUtility() {}
	
	public static final byte WIREFORMAT_INFO = 1;
	public static final byte BROKER_INFO = 2;
	public static final byte CONNECTION_INFO = 3;
	public static final byte SESSION_INFO = 4;
	public static final byte CONSUMER_INFO = 5;
	public static final byte PRODUCER_INFO = 6;
	public static final byte TRANSACTION_INFO = 7;
	public static final byte DESTINATION_INFO = 8;
	public static final byte REMOVE_SUBSCRIPTION_INFO = 9;
	// other constants ignored
}
使用工具类定义常量后,当需要引用某个常量时只需要使用类似于 CommandTypesUtility.WIREFORMAT_INFO 的方式即可。而如果在同一个类里需要大量使用 CommandTypesUtility 中的常量,可以使用静态导入(static import)机制。
import static org.apache.activemq.command.CommandTypesUtility.*;

/**
 * @author wxl24life
 *
 */
public class StaticImportTest {
	byte getWirformat_info() {
		return WIREFORMAT_INFO;
	}
	
	byte getBroker_info() {
		return BROKER_INFO;
	}
	
	// many more other uses 
}
最后引用书中最后一句话:接口应该只被用于定义类型,它们不应该被用来导出常量
总结: 由于阅读源码的过程更多的是在学习和积累知识,遇到新鲜用法或者知识上的盲点是非常正常的,比如这里的常量接口,通过迅速的搜索相关知识点,经过一定的分析,无论是最终接受还是推倒它,对自己而言都是一种收获。另外,结合实际用例会帮助理解并加深对所读书中知识的印象,其实 Effective Java 这本书我经常在翻阅,条目19虽然只有简短到不足两页的篇幅,但是没有碰到实际的使用场景导致在碰到常量接口时完全没有印象。
完。
分享到:
评论
2 楼 wxl24life 2014-10-08  
aliahhqcheng 写道
觉得接口常量和工具类常量比较,唯一的好处就是不用写public static final了。我是程序员,我很懒。哈哈。 看了你的几篇文章,还不错。加油。


谢谢,同加油
1 楼 aliahhqcheng 2014-09-26  
觉得接口常量和工具类常量比较,唯一的好处就是不用写public static final了。我是程序员,我很懒。哈哈。 看了你的几篇文章,还不错。加油。

相关推荐

    消息队列:ActiveMQ:ActiveMQ的高级特性:虚拟目的地与代理.docx

    消息队列:ActiveMQ:ActiveMQ的高级特性:虚拟目的地与代理.docx

    spring整合Activemq源码

    2. **ActiveMQ介绍**:ActiveMQ是Apache软件基金会的顶级项目,是一个开源的消息中间件,遵循JMS(Java Message Service)规范,支持多种协议,如AMQP、STOMP等,提供高可用性、高性能和灵活的消息传递服务。...

    ActiveMQ的处理模式:PTP与PUB/SUB

    在这种模式下,每个消息只有一个消费者,消息发送者将消息放入队列,消费者从队列中取出并消费消息。队列中的一条消息在被一个消费者处理后会被自动删除,因此,同一消息不会被多个消费者处理。在SpringBoot中配置和...

    activemq5.9源码

    通过研究这个源码包,开发者可以理解ActiveMQ如何处理消息的发布/订阅、队列、事务、红elivery策略等,以及如何自定义和扩展其功能,对于深入学习消息中间件和分布式系统有极大的帮助。同时,这也有助于开发者解决...

    消息队列:ActiveMQ:ActiveMQ消息类型:点对点与发布订阅.docx

    消息队列:ActiveMQ:ActiveMQ消息类型:点对点与发布订阅.docx

    ActiveMQ 5.7源码API

    《ActiveMQ 5.7源码API详解》 Apache ActiveMQ是开源的、高性能的、功能丰富的消息中间件,它遵循JMS(Java Message Service)规范,为分布式系统提供了可靠的消息传递服务。ActiveMQ 5.7版本是其重要的一个里程碑...

    ActiveMQ 5.7源码及jar包

    5. **集群与高可用性**:ActiveMQ支持集群模式,通过源码可以学习到如何配置和管理集群,实现消息的负载均衡和故障转移。 6. **安全与认证**:ActiveMQ支持JAAS(Java Authentication and Authorization Service)...

    activeMQ 源码分析

    ### ActiveMQ源码分析 #### 一、ActiveMQ的核心线程功能及生命周期 在深入了解ActiveMQ之前,我们先从整体架构出发,理解ActiveMQ中核心线程的作用及其生命周期。ActiveMQ作为一个高性能的消息中间件,其核心线程...

    Spring和ActiveMQ的整合实例源码

    2. **Spring JMS模块**:Spring框架的JMS模块提供了一个抽象层,使得开发者无需直接操作JMS API,而是通过Spring的模板和监听器接口来处理消息。这提高了代码的可测试性和可维护性。 3. **ActiveMQ配置**:在Spring...

    activemq 5.7 官方源代码

    从Java角度来看,ActiveMQ的源代码也提供了很好的学习材料,例如: - 使用设计模式:ActiveMQ大量运用了工厂模式、观察者模式、适配器模式等,这有助于理解如何在大型项目中有效地组织代码。 - 多线程和并发:在处理...

    activemq 5.5 源码

    这个源码包为开发者提供了了解和学习ActiveMQ实现细节的机会。 源码分析可以从以下几个关键知识点开始: 1. **JMS接口**:ActiveMQ是JMS规范的实现者,提供了生产、消费、管理消息的API。理解JMS接口(如...

    ActiveMQ 5 java 源码

    3. **连接和会话管理**:ActiveMQ提供了JMS(Java Message Service)接口,源码揭示了如何创建、管理和关闭JMS连接、会话和消费者。 4. **消息模型**:在源码中,你可以看到队列(Queue)和主题(Topic)两种消息...

    ActiveMQ学习 完整例子

    - **JMS(Java Message Service)**:JMS是Java平台上的标准,定义了消息生产和消费的接口,ActiveMQ是实现JMS规范的服务器。 - **消息模型**:包括点对点(Queue)和发布/订阅(Topic)两种模型,分别对应于一对...

    ActiveMQ In Action及其源码

    总的来说,《ActiveMQ In Action》及其源码是学习和掌握ActiveMQ不可或缺的参考资料,无论你是初学者还是经验丰富的开发者,都能从中受益匪浅。通过学习和实践,你可以更好地利用ActiveMQ构建可靠、高效的分布式系统...

    activeMQ 详细教程与源码(包含消费者与生产者)

    在本教程中,我们将深入理解 ActiveMQ 的核心概念、使用方式以及如何通过源码学习其工作原理。首先,让我们了解消息队列的基本概念:消息队列是一种异步通信机制,它允许应用程序之间通过发送和接收消息来交换数据,...

    activeMQ5.8源码

    在ActiveMQ 5.8版本中,我们可以通过源码分析来深入了解其内部工作原理和设计模式。 1. **JMS接口与实现**:ActiveMQ作为JMS提供者,实现了JMS规范中的ConnectionFactory、Destination、MessageProducer、...

    linux-apache-activemq-5.15.3和 linux-jdk1.8

    了解这些基础知识后,开发者可以进一步学习如何创建和管理队列、主题,设置消费者和生产者,以及利用ActiveMQ提供的高级特性如虚拟主题、网络连接和代理集群等。同时,掌握JDK 1.8的新特性和最佳实践,能帮助编写更...

    Instant Apache ActiveMQ Messaging Application Development How-to源码

    通过深入学习和实践`Instant Apache ActiveMQ Messaging Application Development How-to源码`,开发者可以掌握如何在自己的应用中有效地利用ActiveMQ,实现高效、可靠的异步通信和解耦。这将有助于构建可扩展的、...

    activemq-5.16.2-源码包,源码包资源

    开发者可以从测试代码中学习如何编写测试用例和保证代码的健壮性。 "资源达人分享计划"的标签表明这是一个社区共享的资源,意味着你可以在社区中寻求帮助,或者分享你对ActiveMQ的理解和经验。研究和理解ActiveMQ的...

    Apache ActiveMQ学习笔记【原创:mq的方式有两种:点到点和发布/订阅】

    ### Apache ActiveMQ 学习笔记 #### 一、ActiveMQ简介与安装 ##### 1.1 ActiveMQ概述 Apache ActiveMQ 是一个完全支持 JMS 1.1 和 J2EE 1.4 规范的消息服务器。它适用于 Java 消息服务 (JMS),并且是一个开源项目...

Global site tag (gtag.js) - Google Analytics