一日一摸之第一日:工厂模式

 
工厂模式(Factory Pattern)
工厂模式主要为创建对象提供了接口,工厂模式按照《java与模式》中的提法分为3类:
1、简单工厂模式(Simple Factory)
2、工厂方法模式(Factory Method)
3、抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性
还有一种分类方法就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。
需要使用工厂模式的情况:
1、在编码时不能预见需要创建哪种类的实例;
2、系统不应该依赖于产品类实例如何被创建、组合和表达的细节。
下面开始对三种类型的工厂模式进行详细说明。
 
一、简单工厂模式
角色组成:
工厂类角色:模式核心,含有一定的商业业务逻辑和判断逻辑,往往由一个具体类实现;
抽象产品角色:一般是具体产品继承的父类或者实现的接口,往往是接口或者抽象类;
具体产品角色:工厂类所创建的对象就是这类角色的实例。
例子如下(FactoryPattern.java JDK1.5编译测试通过):
/**
 *工厂模式测试
 *@author tsimgsong
 *@version 1.0,09/04/2007
 */
public class FactoryPattern{
   public static void main(String[] args){
          Fruit f;
          try{
        f = FruitShop.buy("apples");
          f.eatMethod();
          }catch(UnAvailableProduct e){
             System.out.println("出错原因:"+e.getMessage());
          }
   }
 
}
/**
 *抽象产品角色
 */
interface Fruit{
    void eatMethod();
    void growFrom();
    }
    /**
     *具体产品角色之一
     */
    class Apple implements Fruit{
           public Apple(){
                System.out.println("You create an Apple");
          }
          public void eatMethod(){
               System.out.println("You are eating an Apple");
          }
 
        public void growFrom(){
              System.out.println("Apple tree");
        }
 
    }
       /**
        *具体产品角色之二
        */
       class Orange implements Fruit
       {  
              public Orange(){
                     System.out.println("You create an Orange");
              }
              public void eatMethod(){
                     System.out.println("You are eating an Orange");
              }
              public void growFrom(){
                     System.out.println("Orange Tree");
              }
       }
       /**
        *工厂模式核心:工厂类
        */
 
       class FruitShop
       {  
              /**
               *根据参数生成相应的产品
               *@param type 产品类型
               */
              public static Fruit buy(String type) throws UnAvailableProduct{
                     if(type.equalsIgnoreCase("apple")){
                            return new Apple();
                     }else if(type.equalsIgnoreCase("orange")){
                            return new Orange();
                     }else{
                            throw new UnAvailableProduct("尚未上市");
                     }
 
              }
       }
 
       class UnAvailableProduct extends Exception
       {
              public UnAvailableProduct(String msg){
                     super(msg);
              }
       }
 
分析:当增加一个具体产品类的时候,只要复核抽象产品定制的规则,也即实现或者继承了抽象产品类,只要在工厂类注册就可以生成使用。从具体产品的角度来看,是满足开闭原则的,对扩展开放同时对修改关闭,但从工厂的角度而言又不满足开闭开闭原则,每增加一类具体产品,都必须要修改工厂类,增加相应的商业业务逻辑和判断逻辑。同时在实际应用中,很可能产品是一个多层次的树状结构,而简单工厂模式只有一个工厂类对应这些产品,这种模式对于业务简单的时候可以满足应用,而对于复杂的业务环境可能能力不够。
 
二、工厂方法模式
角色组成:
抽象工厂角色:工厂方法模式的核心,具体工厂角色必须实现的或者继承的父类,通过抽象类或者接口来表现,在前面的简单工厂模式的工厂的基础上抽象出工厂的工厂
具体工厂角色:含有与具体业务逻辑有关的代码,由应用调用以创建具体的产品。由具体类实现
抽象产品角色:同上
具体产品角色:同上
在前面一个例子的基础上,如果商店越来越多,有的专卖水果,有的专卖蔬菜,有的专卖肉类,需要一个管理机构公司来管理,通过这个机构来生成具体的商店,由公司来指定具体的商店,在商店可以买到相应商品。
在上例的基础上修改如下:(FactoryPattern.java JDK1.5测试通过)
/**
 *工厂模式测试
 *@author tsimgsong
 *@version 1.0,09/04/2007
 */
public class FactoryPattern{
   public static void main(String[] args){
          Food f;
          Corp corp;
          try{
                 corp = new FreshShop();
        f = corp.buy("pig");
          f.eatMethod();
          }catch(UnAvailableProduct e){
             System.out.println("出错原因:"+e.getMessage());
          }
   }
 
}
    /**
     *工厂模式核心:抽象工厂角色
     */
    interface Corp {
              Food buy(String type) throws UnAvailableProduct;
       }
    /**
     *具体工厂角色:水果商店工厂类
     *
     */
       class FruitShop implements Corp
       {  
              /**
               *根据参数生成相应的产品
               *@param type 产品类型
               */
              public Food buy(String type) throws UnAvailableProduct{
                     if(type.equalsIgnoreCase("apple")){
                            return new Apple();
                     }else if(type.equalsIgnoreCase("orange")){
                            return new Orange();
                     }else{
                            throw new UnAvailableProduct("尚未上市");
                     }
              }
       }
 
       /**
        *具体工厂角色:肉类商店工厂类
        */
       class FreshShop implements Corp{
              public Food buy(String type) throws UnAvailableProduct{
                     if(type.equalsIgnoreCase("pig")){
                            return new Pig();
                     }else if(type.equalsIgnoreCase("goat")){
                            return new Goat();
                     }else{
                            throw new UnAvailableProduct("尚未上市");
                     }
              }
 
       }
 
    /**
     *抽象产品角色
     */
    interface Food{
        void eatMethod();
        void growFrom();
    }
       /**
        *具体产品角色 水果
        */
 
    class Apple implements Food{
           public Apple(){
                System.out.println("You create an Apple");
          }
          public void eatMethod(){
               System.out.println("You are eating an Apple");
          }
 
        public void growFrom(){
              System.out.println("Apple tree");
        }
 
    }
       /**
        *具体产品角色之一 水果
        */
       class Orange implements Food
       {  
              public Orange(){
                     System.out.println("You create an Orange");
              }
              public void eatMethod(){
                     System.out.println("You are eating an Orange");
              }
              public void growFrom(){
                     System.out.println("Orange Tree");
              }
       }
       /**
        *具体产品角色
        */
 
       class Pig implements Food
       {
              public Pig(){
                     System.out.println("You create an Pig");
              }
              public void eatMethod(){
                     System.out.println("You are eating an Pig Fresh");
              }
              public void growFrom(){
                     System.out.println("Pig grow From");
              }
       }
       /**
        *具体产品角色
        */
 
       class Goat implements Food
       {
              public Goat(){
                     System.out.println("You create an Goat");
              }
              public void eatMethod(){
                     System.out.println("You are eating an Goat Fresh");
              }
              public void growFrom(){
                     System.out.println("Goat grow From");
              }
       }
 
 
       class UnAvailableProduct extends Exception
       {
              public UnAvailableProduct(String msg){
                     super(msg);
              }
       }
工厂方法使用一个抽象工厂角色作为核心来代替在简单工厂模式中使用具体工厂类作为核心,当有新的产品加入时,只要按照抽象产品角色、抽象工厂角色提供的合同来完成,就可以被客户使用,而不必去修改任何已有的代码,完全符合开闭原则。
 
三、抽象工厂模式
抽象工厂模式是一种比工厂模式抽象成都更高的模式。这种模式是由一个工厂类层次和N个产品类层次组成,从每一个产品类层次中提取出一个产品类形成产品家族,这个类族的实例为产品族,产品族中的产品之间有一种依赖关系,一个具体的工厂类负责创建产品族中的各个产品。
抽象工厂模式的本意要求我们创建具体产品对象时,客户端不能暗示任何具体产品对象类型的信息,但是通过分析模式的通信接口可知,客户端可以告诉工厂类这些具体产品的父类。
关键点在于产品体系,如笔记本,有 IBM 的笔记本, DELL 的笔记本, HP 的笔记本,现在有一个抽象笔记本生产商,具体的生产商有 IBMProducer DELLProducer HPProducer ,对于笔记本都有一系列的组件, CPU RAM KeyBoard ,每个工厂都需要生产 CPU RAM KeyBoard 。在生成具体的工厂类的时候就确定了后面要生产的 CPU RAM 或者 KeyBoard 的具体对象。
例子如下(AbstractFactory.java JDK1.5测试通过)
/**
 *抽象工厂类示例
 *@author tsimgsong
 *@version 1.0,09/04/2007
 */
 class TestAbstractFactory{
        public static void main(String[] args){
               AbstractFactory factory = new IBMFactory();
               factory.createCPU();
        }
}
 
/**
 *抽象工厂
 */
public interface AbstractFactory{
    CPU createCPU();
       RAM createRAM();
       KeyBoard createKeyBoard();
}
 
/**
 *具体工厂 IBM ,生产IBM笔记本所需要的所有产品体系
 */
class IBMFactory implements AbstractFactory
{
        public CPU createCPU(){
               return new IBMCPU();
        }
        public RAM createRAM(){
               return new IBMRAM();
        }
        public KeyBoard createKeyBoard(){
               return new IBMKeyBoard();
        }
}
/**
 *具体工厂 DELL ,生产DELL笔记本所需要的所有产品体系
 */
class DELLFactory implements AbstractFactory
{
        public CPU createCPU(){
               return new DELLCPU();
        }
        public RAM createRAM(){
               return new DELLRAM();
        }
        public KeyBoard createKeyBoard(){
               return new DELLKeyBoard();
        }
}
/**
 *具体工厂 HP,生产HP笔记本所需要的所有产品体系
 */
class HPFactory implements AbstractFactory
{
        public CPU createCPU(){
               return new HPCPU();
        }
        public RAM createRAM(){
               return new HPRAM();
        }
        public KeyBoard createKeyBoard(){
               return new HPKeyBoard();
        }
}
 
/**
 *抽象产品类 CPU
 */
abstract class CPU
{
}
/**
 *抽象产品类 RAM
 */
abstract class RAM
{
}
/**
 *抽象产品类 KeyBoard
 */
abstract class KeyBoard
{
}
/**
 *具体产品类
 */
class IBMCPU extends CPU
{
       public IBMCPU(){
              System.out.println("new IBMCPU");
       }
}
class DELLCPU extends CPU
{
       public DELLCPU(){
              System.out.println("new DELLCPU");
       }
}
class HPCPU extends CPU
{
       public HPCPU(){
              System.out.println("new HPCPU");
       }
}
class IBMRAM extends RAM
{
       public IBMRAM(){
              System.out.println("new IBM Ram");
       }
}
class DELLRAM extends RAM
{
       public DELLRAM(){
              System.out.println("new DELL Ram");
       }
}
class HPRAM extends RAM
{
       public HPRAM(){
              System.out.println("new HP Ram");
       }
}
 
class IBMKeyBoard extends KeyBoard
{
       public IBMKeyBoard(){
              System.out.println("new IBM KeyBoard");
       }
}
class DELLKeyBoard extends KeyBoard
{
       public DELLKeyBoard(){
              System.out.println("new DELL KeyBoard");
       }
}
class HPKeyBoard extends KeyBoard
{
       public HPKeyBoard(){
              System.out.println("new HP KeyBoard");
       }
}
在生产笔记本时,只要制定正确的笔记本产生,对具体的组件就无需再传递任何信息就可以生产出正确的组件。一个具体的工厂生产的是一个能构成产品体系的产品。如果说现在需要增加一种新的产品,如笔记本同时需要生产mouse,需要修改的包括,增加一个mouse抽象类或接口,针对各个厂商实现具体的mouse实现类,修改各个抽象工厂接口,增加生产mouse的方法,修改各个具体工厂类。
在一篇网文中提出了一个改进的方案,改进方案引用如下
http://www.ojava.net/read.php?tid=7243,部分内容做了修改)
改革抽象工厂
有没有觉得要改动的地方有点多呢 , 下面我们来改革一下
1.      组件工厂中的
生产文本组件 ();
生产标签组件 ();
...
都改为
生产组件 ( 组件标识 );
要做到上面的,需要做以下几件事情
1.
增加一个 Annotation 来说明后面增加的 组件注册表
@interface
组件描述 {
   Class
组件类 ();
   
}
2.
增加一个 Enum
enum
组件注册表 {
   /**
    * Linux_
文本 的对应实体类为 Linux 文本
    */
   @
组件描述 ( 组件类 = Linux 文本 .class)
   Linux_
文本 ,
   
   @
组件描述 ( 组件类 = Linux 标签 .class)
   Linux_
标签 ,
   
   @
组件描述 ( 组件类 = Windows 文本 .class)
   Windows_
文本 ,
   
   @
组件描述 ( 组件类 = Windows 标签 .class)
   Windows_
标签 ,
}
3.
我们不再需要
interface
组件工厂, class Windows 标签组件工厂, class Linux 组件工厂
我们把 接口 组件工厂改为实体类
为了保持可以扩展和维护
我们定义了一个 接口 工厂
interface
工厂 {
}
class
组件工厂 implements 工厂 {
   public
组件 生产组件 ( 组件注册表 ID) throws Exception {
       try {
           Field f =
组件注册表 .class.getField(ID.toString());
           
组件描述 描述 = f.getAnnotation( 组件描述 .class);
           Class
组件类 = 描述 . 组件类 ();
           return (
组件 ) 组件类 .newInstance();
           //
注意 , 组件类 .newInstance(); 的调用的时候要确保这个组件类有个不带参数的构造函数
           //
如果要使用带参数的构造函数 , 可以在 @interface 组件描述 中增加一个成员
           //
构造函数 [] 构造函数参数 () default{};
           // @interface
构造函数 {Class[] 构造函数的参数 ();}
           //
通过 组件类 .getConstructors(); 来得到这个类的不同构造方法
           //
这样就可以根据用户提供的信息用不同的构造函数实例话对象
           //
带不同的构造函数 , 这里先不讨论,后面我会给出代码
       } catch (Exception e) {
           throw new Exception ("
没有找到对应的组件 ");
       }
   }
}

经过上面的修改 , 代码如下

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;

@Retention(RetentionPolicy.RUNTIME)
@interface
组件描述 {
   Class
组件类 ();
   
}

enum
组件注册表 {
   @
组件描述 ( 组件类 = Linux 文本 .class)
   Linux_
文本 ,
   
   @
组件描述 ( 组件类 = Linux 标签 .class)
   Linux_
标签 ,
   
   @
组件描述 ( 组件类 = Windows 文本 .class)
   Windows_
文本 ,
   
   @
组件描述 ( 组件类 = Windows 标签 .class)
   Windows_
标签 ,
}

interface
组件 {}

interface
文本 extends 组件 {}

interface
标签 extends 组件 {}

class Linux
文本 implements 文本 {
   public String toString() {
       return "Linux
文本 ";
   }
}

class Linux
标签 implements 标签 {
   public String toString() {
       return "Linux
标签 ";
   }
}

class Windows
文本 implements 文本 {
   public String toString() {
       return "Windows
文本 ";
   }
}

class Windows
标签 implements 标签 {
   public String toString() {
       return "Windows
标签 ";
   }
}

interface
工厂 {}

class
组件工厂 implements 工厂 {
   public
组件 生产组件 ( 组件注册表 ID) throws Exception {
       try {
           Field f =
组件注册表 .class.getField(ID.toString());
           
组件描述 描述 = f.getAnnotation( 组件描述 .class);
           Class
组件类 = 描述 . 组件类 ();
           return (
组件 ) 组件类 .newInstance();
       } catch (Exception e) {
           throw new Exception ("
没有找到对应的组件 ");
       }
   }
}

class
客户系统显示 {
   private
文本 text;
   private
标签 label;
   public static void main(String args[]) {
       
客户系统显示 clientOS = new 客户系统显示 ();
       
组件工厂 factory = new 组件工厂 ();
       try {
           clientOS.text = (
文本 ) factory. 生产组件 ( 组件注册表 .Linux_ 文本 );
           clientOS.label = (
标签 ) factory. 生产组件 ( 组件注册表 .Linux_ 标签 );
       } catch (Exception e) {
           e.printStackTrace();
       }
       System.out.println(clientOS.label);
       System.out.println(clientOS.text);
   }
}

这个时候我们增加一个 下拉框
需要改动的地方
1.
增加一个 interface 下拉框 extends 组件 {}
2.
增加 2 个实现类
class Windows
下拉框 implements 下拉框 {}
class Linux
下拉框 implements 下拉框 {}
3.
组件注册表 增加 2 个成员
@
组件描述 ( 组件类 = Linux 下拉框 .class)
Linux_
下拉框 ,    
@
组件描述 ( 组件类 = Windows 下拉框 .class)
Windows_
下拉框 ,
和上面的比起来我们只需要在 组件注册表中增加 2 个成员,而不需要去修改
1.
组件工厂
2.Linux
组件工厂
3.Windows
标签组件工厂
因为这里要修改 3 个地方,是不是觉得麻烦 , 反正我觉得麻烦了点
还有一点就是用户调用的时候不需要再使用 factory. 生产标签组件 (); 等方法,只要一个 factory. 生产组件就可以了 , 这样符合简单工厂的模式


第三部分 带参数的构造函数代码

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

@Retention(RetentionPolicy.RUNTIME)
@interface
构造函数 {
   /**
    *
构造函数的参数类型
    * @return
    */
   Class[]
构造函数的参数 ();
}

@Retention(RetentionPolicy.RUNTIME)
@interface
组件描述 {
   Class
组件类 ();
   
   /**
    *
返回组件的构造函数 <br>
    *
如果长度为 0, 则调用没有参数的构造函数 <br>
    * @return
构造函数 []
    */
   
构造函数 [] 构造函数参数 () default{};
   
}

enum
组件注册表 {
   /**
    * Linux_
文本 的对应实体类为 Linux 文本 <br>
    * Linux
的构造函数有 <br>
    * 1. Linux
文本 (String 显示的文字 ) ; <br>
    * 2. Linux
文本 (String 显示的文字 , Integer 文本字体大小 );
    */
   @
组件描述 ( 组件类 = Linux 文本 .class,
           
构造函数参数 = {@ 构造函数 ( 构造函数的参数 ={String.class}) ,
       @
构造函数 ( 构造函数的参数 ={String.class, Integer.class}) } )
   Linux_
文本 ,
   
   @
组件描述 ( 组件类 = Linux 标签 .class)
   Linux_
标签 ,
   
   @
组件描述 ( 组件类 = Windows 文本 .class)
   Windows_
文本 ,
   
   @
组件描述 ( 组件类 = Windows 标签 .class)
   Windows_
标签 ,
}

interface
组件 {}

interface
文本 extends 组件 {}

interface
标签 extends 组件 {}

class Linux
文本 implements 文本 {
   private String text;
   private Integer size;
   public Linux
文本 (String text) {
       this.text = text;
   }
   public Linux
文本 (String text, Integer size) {
       this.text = text;
       this.size = size;
   }
   public String toString() {
       return "Linux
文本 " + (text == null ? "":", 文本内容为 :"+text) + (size == null ? "":", 文本字体大小为 :"+size);
   }
}

class Linux
标签 implements 标签 {
   public String toString() {
       return "Linux
标签 ";
   }
}

class Windows
文本 implements 文本 {
   public String toString() {
       return "Windows
文本 ";
   }
}

class Windows
标签 implements 标签 {
   public String toString() {
       return "Windows
标签 ";
   }
}

interface
工厂 {}

class
组件工厂 implements 工厂 {
   public
组件 生产组件 ( 组件注册表 ID, Object[] 参数 ) throws Exception {
       try {
           Field f =
组件注册表 .class.getField(ID.toString());
           
组件描述 描述 = f.getAnnotation( 组件描述 .class);
           Class
组件类 = 描述 . 组件类 ();
           
构造函数 [] ano = 描述 . 构造函数参数 ();
           if (
参数 != null) {
               for (int i = 0; i < ano.length; i++) {
                   
构造函数 temp = ano;
                   Class[]
构造函数S = temp.构造函数的参数();                    
                   if (
参数.length == 构造函数S.length) {
                       for (int j = 0; j <
参数.length; j++) {
                           if (
参数[j].getClass().toString().equals(构造函数S[j].toString())) {
                               if ( j ==
参数.length - 1) {
                                   Constructor cons =
组件类.getConstructor(构造函数S);
                                   return (
组件) cons.newInstance(参数);
                               }
                           } else break;
                       }
                   }
                   continue;
               }
               throw new Exception ("
没有找到对应的组件");
           } else
               return (
组件) 组件类.newInstance();
       } catch (Exception e) {
           e.printStackTrace();
           throw new Exception ("
没有找到对应的组件");
       }
   }
}

class
客户系统显示 {
   private
文本 text;
   private
标签 label;
   public static void main(String args[]) {
       
客户系统显示 clientOS = new 客户系统显示();
       
组件工厂 factory = new 组件工厂();
       try {
           Object [] params = {"
初始化文本", new Integer(20)};
           clientOS.text = (
文本) factory.生产组件(组件注册表.Linux_文本,params);
           clientOS.label = (
标签) factory.生产组件(组件注册表.Linux_标签,null);
           System.out.println(clientOS.label);
           System.out.println(clientOS.text);
           Object [] params2 = {"
初始化"};
           clientOS.text = (
文本) factory.生产组件(组件注册表.Linux_文本,params2);
           System.out.println(clientOS.text);
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}
 
ref:
1、 http://www.jdon.com/designpatterns/designpattern_factory.htm
2、 http://www.pcworld.com.cn/how_to_use/1/2006/0714/6926.shtml
4、 http://www.ojava.net/read.php?tid=7243
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值