论坛首页 Java企业应用论坛

工厂方法(Factory Method)模式【创建模式第三篇】

浏览 2418 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-10-23   最后修改:2010-10-20
工厂方法(Factory Method)模式
1、工厂方法模式是类的创建模式,又叫做虚拟构造子模式或者多态性工厂模式
   工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
  
一般而言工厂方法模式的系统设计到以下几种角色:
1) 抽象工厂(Creator)角色:担任这个角色的是工厂方法模式的核心,它是与应用程序无关的,
    任何在模式之中个窗对象的工厂类必须实现这个接口,在实际系统中,这个角色也使用抽象类实现
   
2) 具体工厂(Concrete Creator)角色:担任这个角色的是实现了抽象工厂接口的具体java类。
    具体工厂角色含有与用应密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
   
3) 抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口,
    在实际应用中,这个角色也常常使用抽象java类实现
   
4) 具体产品角色:这个角色实现了抽象产品角色所声明的接口。工厂方法模式所创建的每一个对象都是某个具体产品角色的实例
2、举例:
	//抽象工厂(角色)接口
	public interface Creator{
		//工厂方法
		public Product factory();
	}
	
	//抽象产品(角色)接口
	public interface Product{
	
	}				//一个没有声明任何方法的接口叫做标识接口
	
	//具体工厂(角色)类
	public class ConcreteCreator1 implements Creator{
		//工厂方法
		public Product factory(){
			return new ConcreteProduct1();
		}
	}
	
	public class ConcreteCreator2 implements Creator{
		//工厂方法
		public Product factory(){
			return new ConcreteProduct2();
		}
	}
	
	//具体产品(角色)类
	public class ConcreteProduct1 implements Product{
		public ConcreteProduct1(){
			//do somthing
		}
	}
	
	public class ConcreteProduct2 implements Product{
		public ConcreteProduct2(){
			//do somthing
		}
	}
	
	//客户端(角色)类
	public class Client{
		private static Creator creator1,creator2;
		private static Product prod1,prod2;
		
		public static void main(String args[]){
			creator1 = new ConcreteCreator1();
			prod1 = creator1.factory();
			creator2 = new ConcreteCreator2();
			prod2 = creator2.factory();
		}
	}


Client对象的活动可以分为两部分
1) 客户端创建 ConcreteCreator1 对象,这时客户端所持有变量的静态类型是Creator,而实际类型是 ConcreteCreator1,然后,客户端调用 ConcreteCreator1 对象的工厂方法 factory() ,接着后者调用 ConcreteProduct1 的构造子创建出产品对象
2、举例:
		//抽象工厂角色(水果园丁)
		public interface FruitGardener{
			//工厂方法
			public Fruit factory();
		}
		
		//具体工厂类(苹果园丁)
		public class AppleGardener implements FruitGardener{
			public Fruit factory(){
				return new Apple();
			}
		}
		
		//......(草莓园丁)
		public class StrawberryGardener implements FuritGardener{
			public Fruit factory(){
				return new Strawberry();
			}
		}
		
		//......(葡萄园丁)
		public class GrapeGardener implements FuritGardener{
			public Fruit factory(){
				return new Grape();
			}
		}
		
		//抽象产品角色(水果接口)
		public interface Fruit{
			void grow();
			void harvest();
			void plant();
		}
		
		//具体产品角色(苹果类)
		public class Apple implements Fruit{
			private int treeAge;
			
			public void grow(){
				log("Apple is growing...");
			}
			
			public void harvest(){
				log("Apple has been harvested.");
			}
			
			public void plant(){
				log("Apple has been planted.");
			}
			
			public static void log(String msg){
				System.out.println(msg);
			}
			
			public int getTreeAge(){
				return treeAge;
			}
			
			public void setTreeAge(int treeAge){
				this.treeAge = treeAge;
			}
		}
		//其他同上..........................

3、工厂方法返还的类型
工厂返还的应当是抽象类型,而不是具体类型,只有这样才能保证整队产品的多态性,调用该工厂方法的客户端可以针对抽象编程,依赖于一个抽象产品类型,而不是具体产品类型。
在特殊情况下,工厂方法仅仅返还一个具体产品类型,这个时候工厂方法模式的功能就退化了,表现为针对产品角色的多态性的丧失,客户端从工厂方法的静态类型可以知道将要得到的是什么类型的对象,而这违背了工厂方法模式的用意

4、与其他模式的关系

1、模板方法模式
工厂方法模式常常与模板方法模式一起联合使用,其原因有二:
一、两个模式都是基于方法的,工厂方法模式是基于多态性的工厂方法的,而模板方法模式是基于模板方法和基于方法的
二、两个模式的哦将具体工作交给子类,工厂方法模式将创建工作推延给子类,模板方法模式将生于逻辑交给子类

2、MVC模式
工厂方法模式总是设计到两个等级结构中的对象,而这两个等级结构可以分别是MVC模式中的控制器和视图。一个MVC模式可以有多个控制器和多个视图,控制器端可以创建合适的视图断,如同工厂角色创建合适的对象角色一样,模型端则可以充当这个创建过程的客户端

3、亨元模式
使用了带有逻辑的工厂方法

4、备忘录模式
亨元模式使用了一个聚集来等级所创建的产品对象,以便可以通过查询这个聚集找到和共享已经创建了的产品对象,这就是备忘录模式的应用
5、举例:
		问题:某一个商业软件产品需要支持Sybase和Oracle数据库。这个系统需要这样一个查询运行期系统,根据客户需要,可以随时向Sybase和Oracle数据库引擎发出查询
		答案:可以看出,这个系统是由一个客户端Client,一个抽象工厂角色QueryRunner,两个具体工厂角色SybaseQueryRunner和OracleQueryRunner,以及产品角色组成的
		对于客户端Client而言,系统的抽象产品角色是ResultSet接口,而具体产品角色就是java.sql.Connection所返还的具体ResultSet对象,createSql()方法和createConnection()方法实际上也是工厂方法,他们的产品是SQL语句和Connection对象
		//java抽象类QueryRunner
		import java.sql.Connection;
		import java.sql.ResultSet;
		
		public abstract class QueryRunner{
			public ResultSet run() throws Exception{
				Connection conn = createConnection();
				String sql = createSql();
				return runSql(conn,sql);
			}
			protected abstract Connection createConnection();
			protected abstract String createSql();
			protected abstract ResultSet runSql(Connection conn.String sql)throws Exception;
		}
		
		//具体工厂类
		import java.sql.Connection;
		import java.sql.Statement;
		import java.sql.ResultSet;
		
		public class SybaseQueryRunner extends QueryRunner{
			public Connection createConnection(){
				return null;
			}
			
			protected String createSql(){
				return "select * from customers";
			}
			
			protected ResultSet runSql(Connection conn,String sql) throws Exception{
				Statement stmt = conn.createStatement();
				return stmt.executeQuery(sql);
			}
		}
		
		//具体工厂类
		import java.sql.Connection;
		import java.sql.Statement;
		import java.sql.ResultSet;
		
		public class OracleQueryRunner extends QueryRunner{
			public Connection createConnection(){
				return null;
			}
			
			protected String createSql(){
				return "select * from customers";
			}
			
			protected ResultSet runSql(Connection conn, String sql) throws Exception{
				Statement stmt = conn.createStatement();
				return stmt.executeQuery(sql);
			}
		}
		
		//客户端
		import java.sql.ResultSet;
		
		public class Client{
			private static QueryRunner runner;
			
			public static void main(String args[]) throws Exception{
				runner = new SybaseQueryRunner();
				ResultSet rs = runner.run();
			}
		}
		以上给出的答案中,使用了模板方法模式,在QueryRunner中,run()方法就是一个模板方法,这个方法代表一个顶极逻辑:返还产寻的结果ResultSet
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics