电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

爪哇语言工厂方法创立性模式介绍(下)


发布日期:2022/9/26
 

package comjavapatternsfactorymethod;

public class BadPlantException extends Exception

{

public BadPlantException(String msg)

{

super(msg);

}

}

代码清单 例外类 BadPlantException

工厂方法模式应该在什么情况下使用

既然工厂方法模式与简单工厂模式的区别很是微妙那么应该在什么情况下使用工厂方法模式又应该在什么情况下使用简单工厂模式呢?

一般来说如果你的系统不能事先确定那一个产品类在哪一个时刻被实例化从而需要将实例化的细节局域化并封装起来以分割实例化及使用实例的责任时你就需要考虑使用某一种形式的工厂模式

在我们的小花果园系统里我们必须假设水果的种类随时都有可能变化我们必须能够在引入新的水果品种时能够很少改动程序就可以适应变化以后的情况因此我们显然需要某一种形式的工厂模式

如果在发现系统只用一个产品类等级(hierarchy)就可以描述所有已有的产品类以及可预见的未来可能引进的产品类时简单工厂模式是很好的解决方案因为一个单一产品类等级只需要一个单一的实的工厂类

然而当发现系统只用一个产品类等级不足以描述所有的产品类包括以后可能要添加的新的产品类时就应当考虑采用工厂方法模式由于工厂方法模式可以容许多个实的工厂类以每一个工厂类负责每一个产品类等级因此这种模式可以容纳所有的产品等级

在我们的小花果园系统里不只有水果种类的植物而且有蔬菜种类的植物换言之存在不止一个产品类等级而且产品类等级的数目也随时都有可能变化因此简单工厂模式不能满足需要为解决向题我们显然需要工厂方法模式

关于模式的实现

在实现工厂方法模式时有下面一些值得讨论的地方

第一丶在图四的类图定义中可以对抽象工厂(Creator) 做一些变通变通的种类有

抽象工厂(Creator) 不是接口而是抽象类一般而言抽象类不提供一个缺省的工厂方法 这样可以有效地解决怎样实例化事先不能预知的类的问题

抽象工厂(Creator) 本身是一个实类并提供一个缺省的工厂方法 这样当最初的设计者所预见的实例化不能满足需要时后来的设计人员就可以用实工厂类的factory() 方法来置换(Override))父类中factory()方法

第二丶在经典的工厂方法模式中factory()方法是没有参量的在本文举例时加入了参量这实际上也是一种变通

第三丶在给相关的类和方法取名字时应当注意让别人一看即知你是在使用工厂模式

COM技术架构中的工厂方法模式

在微软(Microsoft)所提倡的COM(Component Object Model)技术架构中 工厂方法模式起着关键的作用

在COM架框里Creator接口的角色是由一个叫作IClassFactory的COM接口来担任的而实类ConcreteCreator的角色是由实现IClassFactory接口的类CFactory(见下图)来担任的一般而言对象的创立可能要求分配系统资源要求在不同的对象之间进行协调等等因为IClassFactory的引进所有这些在对象的创立过程中出现的细节问题 都可以封装在一个实现IClassFactory接口的实的工厂类里面这样一来 一个COM架构的支持系统只需要创立这个工厂类CFactory的实例就可以了

微软(Microsoft)的COM(Component Object Model)技术架构是怎样工作的

在上面的序列活动(Sequence Activity)图中用户端调用COM的库函数CoCreateInstance CoCreateInstance在COM架框中以CoGetClassObject实现 CoCreateInstance会在视窗系统的Registry里搜寻所要的部件(在我们的例子中即CEmployee)如果找到了这个部件就会加载支持此部件的DLL当此DLL加载成功后 CoGetClassObject就会调用DllGetClassObject后者使用new操作符将工厂类CFactory实例化

下面DllGetClassObject会向工厂类CFactory搜询IClassFactory接口返还给CoCreateInstance CoCreateInstance接下来利用IClassFactory接口调用CreateInstance函数此时IClassFactory::CreateInstance调用new操作符来创立所要的部件(CEmployee)此外它搜询IEmployee接口在拿到接口的指针后 CoCreateInstance释放掉工厂类并把接口的指针返还给客户端

客户端现在就可以利用这个接口调用此部件中的方法了

EJB技术架构中的工厂方法模式

升阳(Sun Microsystem)倡导的EJB(Enterprise Java Beans)技术架构是一套为爪哇语言设计的 用来开发企业规模应用程序的组件模型我们来举例看一看EJB架构是怎样利用工厂方法模式的请考察下面的序列活动图

在升阳所提倡的EJB技术架构中 工厂方法模式也起着关键的作用

在上面的图中用户端创立一个新的 Context 对象以便利用 JNDI 伺服器寻找 EJBObject在得到这个 Context 对象后就可以使用 JNDI 名 比如Employee 来拿到 EJB 类 Employee 的 Home 接口使用 Employee 的 Home 接口客户端可以创立 EJB 对象比如 EJB 类 Employee 的实例 emp 然后调用 Employee 的各个方法

// 取到 JNDI naming context

Context ctx = new InitialContext ();

// 利用ctx 索取 EJB Home 接口

EmployeeHome home = (EmployeeHome)ctxlookup(Employee);

// 利用Home 接口创立一个 Session Bean 对象

// 这里使用的是标准的工厂方法模式

Employee emp = homecreate ( John Smith);

// 调用方法

empsetTel ();

代码清单 EJB架构中Home接口提供工厂方法以便用户端可以动态地创立EJB类Employee的实例

JMS技术架构中的工厂方法模式

JMS定义了一套标准的API让爪哇语言程序能通过支持JMS标准的MOM(Message Oriented Middleware 面向消息的中间伺服器)来创立和交换消息(message)我们来举例看一看JMS(Java Messaging Service)技术架构是怎样使用工厂方法模式的

在JMS技术架构中 工厂方法模式无处不在

在上面的序列图中用户端创立一个新的 Context 对象以便利用 JNDI 伺服器寻找 Topic 和 ConnectionFactory 对象在得到这个 ConnectionFactory 对象后 就可以利用 Connection 创立 Session 的实例有了 Session 的实例后就可以利用 Session 创立 TopicPublisher的实例并利用Session创立消息实例

Properties prop = new Properties();

propput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory);

propput(ContextPROVIDER_URL file:C:\temp);

// 取到 JNDI context

Context ctx = new InitialContext(prop);

// 利用ctx 索取工厂类的实例

Topic topic = (Topic) ctxlookup(myTopic);

TopicConnectionFactory tcf = (TopicConnectionFactory) ctxlookup(myTCF);

// 利用工厂类创立Connection这是典型的工厂模式

TopicConnection tCon = tcfcreateTopicConnectoin();

// 利用Connection创立Session的实例又是工厂模式

TopicSession tSess = tConcreateTopicSession(false

SessionAUTO_ACKNOWLEDGE);

// 利用Session创立Producer的实例又是工厂模式

TopicPublisher publisher = tSesscreatePublisher(topic);

// 利用Session创立消息实例又是工厂模式

TextMesage msg = tSesscreateTextMessage(Hello from Jeff);

//发送消息

publisherpublish(msg);

代码清单

JMS架构中工厂模式被用于创立 Connection Session Producer 的实例

问答题

在这一节和上一节的类图中我注意到Apple类的类图与Strawberry类的类图有一点点不同在Apple类的类图左上角有一个夹子样的标识请问这个标识代表什么意思

在这一节的类图我注意到 ConcreteProduct 类只出现一次但实现 Product 接口的类实际上可以有很多这是否可以用在联接 Product 和 ConcreteProduct 之间的线旁注上 表示呢? 记得我在UML图中曾见过这种记号

请问在本节的小花果园系统的源代码清单Broccoli 类实现两个接口VeggieIF 和 PlantIF只有 PlantIF 才与工厂模式有关为什么不把 VeggieIF 接口合并到 PlantIF 接口中去?

请问在工厂方法模式中产品(Product) 何时应是抽象类何时应是接口?

请问在工厂方法 (factory())中为什么要使用 if 语句作过程性判断来决定创立哪一个产品类而不使用多形性原则 (Polymorphsm) 来创立产品类?

问答题答案

Apple类有性质(property)而Strawberry类没有性质

一个类的成员变量叫做属性(attribute)性质与属性的区别在于性质是带着一套取值丶赋值方法的属性一个类有了属性其类图左上角就会有一只夹子有些人认为一个爪哇类有了属性才能被称做爪哇豆(Java Bean)这只夹子就表示这个类是一只豆

一个企业爪哇豆或 EJB (Enterprise JavaBean) 的类图左上角也会有一只夹子夹子上面有一个E字以示与普通的爪哇豆的不同(请见下图)

不能在图中联接 Product 和 ConcreteProduct 之间的线有两条一条表示两者之间的推广关系 (即有向上箭头的)另一条表示两者之间

上一篇:设计模式-行为型-迭代器模式(Iterator)

下一篇:最简单的设计模式学习:Singleton模式