设计模式在软件工程中占有重要地位而JavaMail是Java平台的一个扩展为管理电子邮件提供了统一的应用编程接口本文讨论Factory Method设计模式在Javamail中的应用
模式简介
模式的概念最早是出现在城市建筑领域的lexander的一本关于建筑的书中明确的给出了模式的概念用来解决在建筑中的一些问题后来这个概念逐渐的被计算机科学所采纳《Design Patterns: Elements of Reusable ObjectOriented Software》[](以下简称《设计模式》)则堪称设计模式领域的经典书籍之一它开创了软件工程领域的模式化进程
设计模式的简单定义就是对于一类重复出现的问题的可重用的解决方案在软件工程中一个设计模式解决一类软件设计问题设计模式中许多方法其实很早就出现了并且在应用中也比较多但是直到《设计模式》出来之前并没有一种统一的认识或者说那时候并没有对模式形成一个概念这些方法还仅仅是处在经验阶段并没有能够被系统的整理形成一种理论
每一个设计模式都系统的命名解释和评价了面向对象系统中的一个重要的和重复出现的设计这样我们只要搞清楚这些设计模式就可以完全或者说很大程度上吸收了那些蕴含在模式中的宝贵的经验对面向对象的系统能够有更为完善的了解更为重要的是这些模式都可以直接用来指导面向对象系统中至关重要的对象建模问题如果有相同的问题背景那么很简单直接套用这些模式就可以了这可以省去你很多的工作
在《设计模式》一书中涉及到个模式被分类为创建型模式(Creational Patterns)结构型模式(Structural Patterns)和行为模式(Behavioral Patterns)分别从对象的创建对象和对象间的结构组合以及对象交互这三个方面为面向对象系统建模方法给予了解析和指导
其中创建型设计模式(Creational Patterns)描述怎样创建一个对象它隐藏对象创建的细节使程序代码不依赖具体的对象这样当我们增加一个新的对象时几乎不需要修改代码结构型设计模式(Structural Patterns)描述类和对象之间怎么组织起来形成大的结构主要使用继承来组织接口或实现行为型设计模式(Behavioral Patterns)描述算法以及对象之间的任务分配它所描述的不仅仅是对象或类的设计模式还有它们之间的通讯模式
设计模式在Java中得到了广泛应用在《Thinking in Java》[]一书中Bruce Eckel介绍了SingletonPrototypeObserverVisitor等设计模式在Java中的具体应用和实现以下将介绍Factory Method设计模式在Javamail中的应用从中可看出设计模式不仅有助于软件设计对理解软件结构也很有帮助
Javamail简介
经过几年的发展Java语言已相当成熟并在各领域得到广泛应用特别是JEETM(JavaTM Platform Enterprise Edition)的出现更是极大地方便了分布式应用程序的创建作为Java平台的一个扩展JavaMail也是JEETM的技术之一为管理电子邮件提供了统一的应用编程接口(APIApplication Programming Interface)它使服务提供者(service providers)可以使用Java语言为它们自己的邮件或消息处理系统提供一致的接口应用程序可以使用这些一致的接口方便地与这些系统通信
以下是一些Javamail API中的抽象类由它们可以组成典型的邮件系统
Message代表一个电子邮件消息
Folder以分级的形式组织消息一个Folder可以包含多条消息多个Folder
Store代表由邮件服务器 target=_blank>服务器管理的消息数据库一个具体的Store使用一种特殊的访问协议(如PopStore使用Pop协议IMAPStore使用IMAP协议)并可包含一个或多个Folder
Transport代表一个特殊的传输协议一个具体的Transport使用具体的传输协议发送消息
设计模式Factory Method
此模式属于创建型设计模式它只定义创建对象的接口而由它的子类负责创建具体的对象利用子类实例化不同的对象图一是Factory Method 模式结构的类图(Class Diagram)其中:
Product 定义了由factory method所创建对象的统一接口
ConcreteProduct 具体的类实现Product接口
Creator 一般为抽象类声明若干factory method(方法)由它创建类型为Product的对象正因为它能生产对象所以称为factory methodCreator也可能拥有一个方法创建某个缺省的具体对象
ConcreteCreator 重载factory method以创建某个 ConcreteProduct 的具体实例
也就是说Creator依赖于ConcreteCreator创建Product型的ConcreteProduct对象 Factory method使应用程序代码只需处理Product接口而与具体的类(ConcreteProduct)无关增强了代码可重用性因为它独立于用户定义的具体的类
src=http://imgeducitycn/img_///jpg border= twffan=done>
Factory Method在Javamail中的应用
src=http://imgeducitycn/img_///jpg border= twffan=done>
图二指示了Factory Method在Javamail中的应用其中的类Store相当于图一中的CreatorStore的两个子类PopStoreIMAPStore相当于图一中的ConcreteStore类Folder相当于ProductFolder的两个子类PopFolder和IMAPFolder相当于ConcreteProduct而Store中的方法getFolder就是一个factory method由子类PopStore实例化PopFolder由IMAPStore实例化IMAPFolder
类似的图二中的Folder相对于Store来说是Product但相对于Messsage却也是一个Creator其方法getMessage同样也是factory method
可重用性
src=http://imgeducitycn/img_///jpg border= twffan=done>
上表是使用Factory Method模式创建对象和直接创建对象的比较显然前者对于创建不同的对象所用的代码几乎相同便于代码重用而后者对于创建不同的对象所用代码就相差很大想做改动就比较麻烦若想重用就几乎是不可能的设计可重用的面向对象软件是十分不易的恰当地运用设计模式则可在一定程度上解决这个问题
可扩展性
如有一种对应与PopIMAP的新的邮件协议NewP则很容易使系统支持这种新的协议扩展Store建立新类NewPStore扩展Folder建立新类NewPFolder扩展Message建立新类NewPMessage就建立起了新协议的大致框架
Parameterized Factory Method在Javamail中的应用
Factroy Method设计模式还有一个变异Parameterized factory method模式对于Parameterized factory method模式其factory method有一参数用于指明需创建的对象的类型这样一个类的factory method可以创建多种具体类型(ConcreteProduct)的对象与Factory Method相同的是它所创建的对象都具有同样的接口Product
在Javamail中有一个final static类Session不能创建它的子类通过此类设置和访问一些特殊的属性另外此类还拥有若干Parameterized Factory Method可以创建多种对象
可重用性
图三中的getStore和getTransport都是Parameterized Factory Method以getStore为例给参数以不同的值就能创建不同的对象例如
Code highlighting produced by Actipro CodeHighlighter (freeware)
> Session session = SessiongetDefaultInstance(props authenticator);
Store store = sessiongetStore(pop); //实例化PopStore
Store store = sessiongetStore(IMAP); //实例化IMAPStore
如上代码所示通过给出不同的参数即能实例化不同的对象其代码重用是相当简单的
可扩展性
若你新建了一个邮件系统拥有Store的特殊子类NewPStore此类采用特殊的协议NewP并已进行了相关设置如在javamaildefaultproviders文件中设置了
Code highlighting produced by Actipro CodeHighlighter (freeware)
> protocol = NewP; type = store; class = comsunmailIMAPNewPStore;
这样你就可以利用
Session session = SessiongetDefaultInstance(props authenticator);
Store store = sessiongetStore(NewP); //实例化NewStore
创建一个NewPStore型对象
src=http://imgeducitycn/img_///jpg border= twffan=done>
总结
Factory Method及其变异Parameterized factory method 都是极为常用的设计模式在Javamail中还有许多地方使用了Factory Method或Parameterized Factory Method比如类Session中的方法getProvidergetFolder也是Parameterized Factory Method getInstance也可以算是Parameterized Factory Method不过它比较特殊它实例化Session自身而且两者都很容易实现代码重用进行系统扩展
但Factory Method模式和Parameterized factory method略有不同对于Factory Method有一个潜在的不利因素那就是为了创建一个特殊的对象必须有相应于Creator的一个子类如上所述创建一个PopFolder对象必须要有一个Store的子类PopStore 创建一个IMAPFolder对象必须要有一个Store的子类IMAPStore而对于Parameterized factory method只需要一个具体的Creator提供不同的参数就能创建不同的对象所以可视实际情况在这两者之中取捨一般原则是当创建一个具体的Product时确实需要扩展Creator那么就采用Factory Method如Pop和IMAP是两者区别比较大的不同的邮件协议PopStore和IMAPStore差异很大创建PopFolder确实需要有一个特殊的Store扩展PopStore对于IMAP也一样此时就需要采用Factory Method模式而为了创建PopStoreIMAPStore如还是采用Factory Method模式而分别创建了Session的子类PopSessionIMAPSession其意义就不是很大完全是为了创建PopStore而创建PopSessionSessionPopSessionIMAPSession三者代码几乎相同可以说是一种代码冗余
总之应该视具体情况应用适当的设计模式才能充分发挥设计模式应有的作用