一、AndroidPn——IQHandler

在学习工厂方法模式的时候,看到实例代码,感觉以前就见过这种模式的应用。原来,前不久做的有关AndroidPn的项目中,服务器有段代码的形式和工厂方法很相似。

之前,在这篇文章《模拟AndroidPN Client(1)——AndroidPN源码简析》中分析了如何在服务器中处理自定义的xmpp节。

IQHandler处理信息<iq>节的抽象类,注册IQHandler就是继承IQHandler,重写其中的handleIQ(IQ)方法返回应答的<iq>节.

IQHandler的process(IQ)即是处理各种IQ,在实际过程中是IQHandler handler = new IQXXXHandler()。在调用

handler.process()就会调用子类的handleIQ(IQ)方法

再看看代码是如何实现的

   1: public abstract class IQHandler {
   2:  
   3:     //为了代码简洁,删除了try...catch和其余的方法
   4:     public void process(Packet packet) {
   5:         IQ iq = (IQ) packet;
   6:         IQ reply = handleIQ(iq);
   7:         if (reply != null) {
   8:             PacketDeliverer.deliver(reply);
   9:         }
  10:     }
  11:  
  12:     /**
  13:      * Handles the received IQ packet.
  14:      * 
  15:      * @param packet the packet
  16:      * @return the response to send back
  17:      * @throws UnauthorizedException if the user is not authorized
  18:      */
  19:     public abstract IQ handleIQ(IQ packet) throws UnauthorizedException;
  20: }
注意红色的代码
IQ reply = handleIQ(iq);
public abstract IQ handleIQ(IQ packet) throws UnauthorizedException;
不正好和《工厂方法模式》所演示的例子很像吗?
1.首先,业务类(IQHandler)事先是不可能知道客户端会发送什么类型的消息,也就是说IQHandler根本就不应该和具体的消息类(继承抽象类IQ)耦合在一起。
 
2.然而,IQHandler是用来处理客户端发送来的信息,却又不能和具体的信息类型耦合。这时就能用工厂方法模式,业务类(IQHandler)调用工厂方法 public abstract IQ handleIQ(IQ packet),该方法是抽象类型的,具体由子类去实现。
也就是说,比如有X和Y类型的信息:XIQYIQ就分别有XIQHandlerYIQHandler(IQHandler的子类)来分别实现handleIQ(IQ packet)。XIQHandler处理X类型信息,YIQHandler处理Y类型信息。
 
IQHandler不管是何种类型信息,它只管调用工厂方法handleIQ(IQ packet),处理该信息,然后返回处理结果。
由此可以看出
IQHandler相当于Creator
IQ相当于Product
XIQHandler、YIQHandler相当于ConcreteCreator
XIQ、YIQ相当于ConcreteProduct
 
 
二、俄罗斯方块——方块类
Ioc/DI不多作解释,主要就是应用程序不在主动,而是被动等待容器来注入资源。
1.根据面向对象的思想分析俄罗斯方块,可知游戏中下落的每个方法都是一个特定方块类(正方形、长条等等)的实例。这些方块都有一个相同的行为——翻转。
2.在程序中,每个方块对象都是由一个二维数组来表示的,所以方块翻转时,会因方块类型的不同,所对应的二维数组也会不同。
 
补充:这里在简介二位数组表示方块的形式。虽然每种类型的方法翻转样式不同,但其翻转样式是可以事先定义好的。无非就是四个不同的二维数组。
但方块类事先不知道,游戏中会产生哪一种类型的方块(随机产生),需要等待容器注入特定类型的方块资源。这就要用到IoC/DI。
方块类
   1: public abstract class Shape {
   2:     //方块的二维数组表示形式,有4种形式,所以用一个三维数组表示
   3:     protected int[][][] allShape = new int[4][][];
   4:     //方块的当前状态,是二维数组的哪种形式
   5:     private int status;
   6:     
   7:     /**
   8:      * 方块翻转
   9:      */
  10:     public void rorate(){
  11:         status++;
  12:         drawShape(allShape[status]);
  13:     }
  14:     
  15:     /**
  16:      * 画出方块
  17:      * @param shape
  18:      */

19: public void drawShape(int[][] shape){

//根据二维数组所表示的方块,画出该方块

  21:     }
  20:      
  22:     
  23:     /**
  24:      * 注入特定类型的方块资源
  25:      * 实际上就是工厂方法
  26:      */
  27:     public abstract void createShape();
  28: }
特定方块类(Shape的子类)
   1: public class SquareShapre extends Shape {
   2:  
   3:     @Override
   4:     public void createShape() {
   5:         allShape = new int[4][][];
   6:         //定义好方块的四种形式 ......
   7:     }
   8:  
   9: }

 

Shape只管方块的翻转行为,至于什么样的方块由外部注入。注入哪种方块由子类完成。比如要注入方形方块,就由SquareShape类来完成资源(二维数组)注入。

 

工厂方法模式和IoC/DI的思想都是类似的,由于业务上存在不同类型的任务,体现在程序上就是要调用不同类型的对象完成同样的任务。但业务类并不知道由哪种类型的对象,因此需要工厂方法,并且让子类实现工厂方法,返回特定类型的对象,然后业务类再使用这些对象完成任务。