`
songry
  • 浏览: 84384 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Clojure和JAVA设计模式(2) 工厂模式之工厂方法

阅读更多

注:本文基于jdk1.6和Clojure1.2

 

工厂方法

    工厂方法模式定义了一个创建对象的接口,由子类来决定实例化哪一个类,意即将实例化推迟到子类。

 

    当然,这个说法本身是干巴巴概念性的。让我们针对上篇简单工厂 的例子考虑一下,我们在SimpleFactory中

已经定义了产生IProduct实例的方法,这是在调用之前就定好了 产生IProduct实例的规则,可是如果遇到

需要在调用时才决定这个规则的情况时,SimpleFactory就无法满足了。

 

    比如说,某次调用中需要在参数productType等于1时返回Product1, 参数productType等于2时返回

Product2, SimpleFactory正好能满足这种情况,没问题;但另外一次调用时需要在 参数productType等于

1时返回Product2, 参数productType等于2时返回null, 参数productType等于3时返回Product1,

SimpleFactory就傻眼了......

 

     当然,我们一拍脑袋就想出办法了--在SimpleFactory的 factory方法中 再加一个参数来增加规则:

/** 
     * 根据产品类型和规则来生产产品 
     * @param productType 
     * @return 
     */  
    public static IProduct factory(String productType,String regulation){  
    	if(regulation.equals("1")){
	        if(productType.equals("1"))  
	            return new Product1();  
	        else if(productType.equals("2"))  
	            return new Product2(); 
        }else if(regulation.equals("2")){
        	if(productType.equals("1"))  
	            return new Product2();  
	        else if(productType.equals("3"))  
	            return new Product1();
        }
        return null;  
    } 
 

    哈哈,这不就解决问题了吗?这样做确实解决了眼前的问题而且能够正常工作,但是,如果产品的规则再增添

一种,比如regulation3,毫无疑问,我们又需要再去修改SimpleFactory的factory方法;规则再增加一种,好的,

继续修改SimpleFactory的factory方法...以此类推, SimpleFactory的factory方法会变得越来越大,变成冗长

的、逻辑关系复杂的代码泥团,谁要再去修改这个方法,必须仔细研读代码,小心翼翼地添加类型和规则,生怕

影响到了所有调用它的地方。改完之后,大骂一通设计人员,然后到javaeye上面发一篇《碰到史上最烂JAVA项目》

这样的帖子,然后大家告诉你:“国内项目很多都这样,没办法,找到工资待遇高的就走吧”。

 

    问题在于,这种解决方法是面向过程而非面向对象的。记得面向对象的设计原则吗,面向接口而非面向实现类

编程,对修改封闭对扩展开放。所以,工厂方法模式就出场了:

/**
 * 工厂方法接口
 * @author RoySong
 */
public interface IFactoryMethod {

	/**
	 * 根据产品类型生产产品
	 * @param productType
	 * @return
	 */
	public IProduct factory(String productType);
}

/**
 * 规则1工厂
 * @author RoySong
 */
public class Regulation1Factory implements IFactoryMethod {

	@Override
	public IProduct factory(String productType) {
		if(productType.equals("1"))  
            return new Product1();  
        else if(productType.equals("2"))  
            return new Product2();
		return null;
	}

}

/**
 * 规则2工厂
 * @author RoySong
 */
public class Regulation2Factory implements IFactoryMethod {

	@Override
	public IProduct factory(String productType) {
		if(productType.equals("1"))  
            return new Product2();  
        else if(productType.equals("3"))  
            return new Product1();
		return null;
	}

}

/**
 * 工厂方法调用
 * @author RoySong
 */
public class FactoryMethodTest {

	private IFactoryMethod iFactoryMethod;
	
	public static void main(String[] args){
		FactoryMethodTest fmt = new FactoryMethodTest();
		//采用规则1工厂方法
		fmt.setiFactoryMethod(new Regulation1Factory());
		IProduct product1 = fmt.getiFactoryMethod().factory("1");
		product1.use("regulation 1");
		IProduct product2 = fmt.getiFactoryMethod().factory("2");
		product2.use("regulation 1");
		//采用规则2工厂方法
		fmt.setiFactoryMethod(new Regulation2Factory());
		product1 = fmt.getiFactoryMethod().factory("3");
		product1.use("regulation 2");
		product2 = fmt.getiFactoryMethod().factory("1");
		product2.use("regulation 2");
	}

	public void setiFactoryMethod(IFactoryMethod iFactoryMethod) {
		this.iFactoryMethod = iFactoryMethod;
	}

	public IFactoryMethod getiFactoryMethod() {
		return iFactoryMethod;
	}
}
 

    调用的结果是:

Product1 use:regulation 1
Product2 use:regulation 1
Product1 use:regulation 2
Product2 use:regulation 2
 

    而在Clojure当中,工厂方法简直是信手拈来。首先我们定义两个产品:

(defn product1 [msg]
  (println "Product1 use:" msg))
(defn product2 [msg]
  (println "Product2 use:" msg))
 

    然后我们定义两个规则工厂:

(defn regar1-factory [type]
  (cond  
      (= 1 type) #'product1   
      (= 2 type) #'product2
      true nil))

(defn regar2-factory [type]
  (cond  
      (= 3 type) #'product1  
      (= 1 type) #'product2
      true nil))
 

    最后定义一个调用函数:

(defn use-product [fn type msg]
  ((fn type) msg))
 

    我们注意到代码中有一个奇特的符号” #‘ “,这是个什么玩意儿呢?

 

    实际上,这是Clojure中的一种取值方式,用于取得符号(比如product1)所映射的对象值(意即product1所

代表的整个函数体),而并非符号储存的对象的引用值(指针)。换句话说,我们的规则函数(regar*-factory)

所返回的是整个函数,而调用函数接受的参数fn也是一个函数。这就是函数式编程语言的最大特征之一,函数即

数据。你可以把函数作为返回值或者是参数。这也是函数式编程语言比指令式编程语言更加灵活(也更加难懂)的

原因之一。

 

    回到例子,我们开始使用调用函数:

(use-product #'regar1-factory 1 "anything")

    毫无意外的结果:

Product1 use: anything
nil

    再来一个:

(use-product #'regar2-factory 1 "something")

    仍然是预期的结果:

Product2 use: something
nil
 

    这样,我们在Clojure里面就达到了运行时根据规则产生不同的对象的目的了。严格来说,上面的例子并非在

运行时才进行的实例化,应该通过宏(macro)来产生product1和product2,不过,为了代码的清晰和简单,

这儿暂时就这么写了。

 

附注:很久没有写工厂了,概念模糊了,这里面的java代码实际上不是工厂方法,而是抽象工厂。经朋友提醒才

想起来,原文先保留不动吧。

分享到:
评论

相关推荐

    Clojure调用Java类的一个实例

    这是通过Java Interop特性实现的,它允许Clojure代码直接引用Java类、方法和字段。例如,如果你有一个名为`com.example.MyClass`的Java类,你可以这样在Clojure中引用它: ```clojure (def my-class (java.lang....

    Scala与Clojure函数式编程模式:Java虚拟机高效编程1

    书中可能会讨论如何用函数式编程模式替换面向对象编程中的常见模式,如工厂方法、单例、观察者模式等。例如,使用函数式编程可以简化创建对象的过程,通过高阶函数实现单例模式,以及利用反应式编程替代事件驱动。 ...

    JAVA设计模式工厂模式之简单工厂[定义].pdf

    【Java设计模式:工厂模式之简单工厂】 简单工厂模式是一种常用的设计模式,它提供了一种创建对象的最佳方式,尤其在需要根据条件创建不同类的对象时。在Java中,简单工厂模式通过一个工厂类来集中创建对象,避免了...

    clojure.java-time:用于Clojure的Java 8 Date-Time API

    `clojure.java-time`库将Java 8的日期时间对象封装为Clojure记录,这些记录实现了特定的协议,如`clojure.java-time/temporal`, `clojure.java-time/chronology`, 和`clojure.java-time/format`。这样,Clojure用户...

    nginx-clojure:Nginx-Clojure 是一个 Nginx 模块,用于嵌入 Clojure 或 Java 程序-开源

    Nginx-Clojure 是一个 Nginx 模块,用于嵌入 Clojure 或 Java 或 Groovy 程序,通常是那些基于 Ring 的处理程序。 查看 http://nginx-clojure.github.io 了解更多详情

    nginx-clojure:用于嵌入Clojure或Java或Groovy程序的Nginx模块,通常是那些基于Ring的处理程序

    是一个模块,用于嵌入Clojure或Java或Groovy程序,通常是那些基于的处理程序。 核心功能 最新版本是v0.5.2,有关更多详细信息,请参见。 与兼容,显然支持那些基于Ring的框架,例如Compojure等。 通过使用Clojure ...

    读书笔记:Scala与Clojure函数式编程模式Java虚拟机高效编程 >源码.zip

    读书笔记:Scala与Clojure函数式编程模式Java虚拟机高效编程 >源码

    读书笔记:《Scala与Clojure函数式编程模式Java虚拟机高效编程》学习代码记录.zip

    读书笔记:《Scala与Clojure函数式编程模式Java虚拟机高效编程》学习代码记录

    Programming Clojure 英文电子版

    - **Java Integration**:由于Clojure运行在JVM之上,因此它可以无缝地访问Java类库中的所有资源。这种紧密集成意味着开发者可以在Clojure项目中使用Java类库提供的强大功能,而无需进行额外的转换或封装。 - **...

    Clojure编程乐趣]+clojure_programming.pdf

    Clojure是一种基于Lisp家族的函数式编程语言,它运行在Java虚拟机(JVM)上,同时也支持JavaScript和其他平台。Clojure的设计目标是提供一个高效、并发、可移植的环境,适合解决现代软件开发中的复杂问题。在这个...

    clojure电子书

    《Clojure电子书》集合包含了三本关于Clojure编程的重要书籍和一个Leiningen的Windows安装程序,这对于学习和深入理解Clojure语言至关重要。Clojure是一种基于Lisp的函数式编程语言,它运行在Java虚拟机(JVM)上,...

    Java_Clojure编程语言.zip

    Java和Clojure是两种截然不同的编程语言,但它们都在现代软件开发中占有重要的地位。Java,由Sun Microsystems(后被Oracle收购)开发,是一种广泛使用的面向对象的编程语言,以其“一次编写,到处运行”的特性闻名...

    clojure相关书籍2

    【2】clojure_programming.pdf 【3】Practical Clojure.pdf 【4】Programming Clojure with Emacs.pdf 【5】Programming Concurrency on the JVM(Java虚拟机并发编程)(英文版).pdf 【6】programming_clojure_2nd_...

    clojure1.6

    Clojure的设计目标是提供一种与Java平台无缝集成的、并发友好的、动态类型的语言,它强调代码即数据的原则,这使得Clojure程序易于编写、测试和维护。 Clojure 1.6 版本包含了多个关键改进和新特性。首先,它提升了...

    了解java中的Clojure如何抽象并发性和共享状态

    Clojure的设计者Rich Hickey引入了"epochal时间模型"的概念,以解决传统并发编程中的问题,这些问题主要源于Java和其他C基语言中变量的身份和值的交织。 在Clojure中,值是不可变的,这意味着一旦创建,就不能改变...

    clojure1.3.0及资料

    Clojure的设计目标是提供一种静态类型的、并发的、内存安全的语言,同时保持Lisp的简洁性和灵活性。在这个压缩包文件中,包含了一些关于Clojure的重要资源,特别是对于学习和理解Clojure 1.3.0版本非常有帮助。 1. ...

Global site tag (gtag.js) - Google Analytics