设计模式2(工厂模式)

工厂模式分为三类:

 1、简单工厂模式(simple Factory)

 2、工厂方法模式(Factory Method)

 3、抽象工厂模式(Abstract Factory)

 

一:简单工厂模式

简单工厂模式的概念

  就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

简单工厂模式的UML图

  

简单工厂模式代码

  学习简单工厂模式的时候我用的是一个与人类有相关的例子。人类在世界分为男人和女人,首先定义一个Human产品的抽象接口

/**
 * This is factory patter package
 */
package com.roc.factory;

/**
 * 产品的抽象接口  人类
 * @author liaowp
 *
 */
public interface Human {
    
    public void say();

}

然后定义男人和女人,同样都有说话的方法。

/**
 * This is factory patter package
 */
package com.roc.factory;

/**
 * man  男人
 * @author liaowp
 *
 */
public class Man implements Human {

    /* say method
     * @see com.roc.factory.Human#say()
     */
    @Override
    public void say() {
        System.out.println("男人");
    }

}
/**
 * This is factory patter package
 */
package com.roc.factory;

/**女人
 * @author liaowp
 *
 */
public class Woman implements Human {

    /* say method
     * @see com.roc.factory.Human#say()
     */
    @Override
    public void say() {
        System.out.println("女人");
    }

}

最后写一个工厂类,用来创造男人和女人。第一种方式是使用逻辑判断的方式实现的。

package com.roc.factory;
/**
 * 简单工厂
 * @author liaowp
 *
 */
public class SampleFactory {
    public static Human makeHuman(String type){
        if(type.equals("man")){
            Human man = new Man();
            return man;
        }else if(type.equals("womman")){
            Human woman = new Woman();
            return woman;
        }else{
            System.out.println("生产不出来");
            return null;
        }            
    }
}

第二方式是使用java的放射实现的,我觉得这一类的实现方式比较好。

package com.roc.factory;
/**
 * 简单工厂放射实现
 * @author liaowp
 *
 */
public class SampleFactory1 {
    public static Human makeHuman(Class c){
        Human human = null;
        try {
            human = (Human) Class.forName(c.getName()).newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            System.out.println("不支持抽象类或接口");
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("没有足够权限,即不能访问私有对象");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            System.out.println("类不存在");
            e.printStackTrace();
        }    
        return human;
    }
}

最后是客户端的代码

package com.roc.factory;
/**
 * 简单工厂测试
 * @author liaowp
 *
 */
public class Client {
    public static void main(String[] args) {
//        Human man = SampleFactory.makeHuman("man");
//        man.say();
//        Human womman = SampleFactory.makeHuman("womman");
//        womman.say();
//        Human test = SampleFactory.makeHuman("tttt");
        
        Human man = SampleFactory1.makeHuman(Man.class);
        man.say();
        Human woman = SampleFactory1.makeHuman(Woman.class);
        woman.say();
    }
}

 简单工厂模式应用场景 

  优点:工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个 软件体系结构的优化。
     缺点:由于工厂类集中了所有实例的创建逻辑,违反了 高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
作者: 鹏鹏
 

二:工厂方法模式

工厂方法模式的优点:

1、良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。
2、工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或者扩展一个工厂类,就可以完成“拥抱变化”。
3、屏蔽产品类。这一点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需关心产品的接口,只要接口保持不变,系统中的上层模块就不需要发生变化。因为产品类的实例化是由工厂类负责的,一个产品对象具体由哪一个产品产生是由工厂类决定的。
4、工厂方法模式是典型的解耦框架。。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我们不需要的就不要去交流;也符合依赖倒置原则,只依赖产品的抽象类;当然也符合里氏替换原则,使用产品子类替换产品父类,没问题。

 

工厂方法模式的通用代码如下:

?
1
2
3
4
5
6
7
8
9
//抽象产品类 
public abstract class Product {
   //产品类的公共方法 
   public void method1() { 
     //业务逻辑处理 
  
   //抽象方法 
   public abstract void method2();
}

具体的产品类可以有多个,都继承于抽象产品类,源代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
//具体产品类 
public class ConcreteProduct1 extends Product {
   public void method2() { 
     //业务逻辑处理 
  
public class ConcreteProduct2 extends Product {
   public void method2() { 
     //业务逻辑处理 
  
}

抽象工厂类负责定义产品对象的产生,源代码如下:

?
1
2
3
4
5
6
7
//抽象工厂类 
public abstract class Creator { 
   /** 
   *创建一个产品类,其输入参数类型可以自行设置,通常为String,Enum, Class,当然可以为空
   */ 
   public abstract <T extends Product> T createProduct(Class<T> cls);
}

具体如何产生一个产品的对象,是有具体的工厂类实现的,源代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
//具体工厂类 
public class ConcteteCreator extends Creator { 
   public <T extends Product> T createProduct(Class<T> cls) { 
     Product product = null
     try
       product = (Product)Class.forName(cls.getName()).newInstance();
     } catch (Exception e) { 
       //异常处理 
    
     return (T)product; 
  
}

场景类的调用方法如下代码:

?
1
2
3
4
5
6
7
8
9
10
//场景类 
public class Client { 
   public static void main(String[] args) { 
     Creator creator = new ConcreteCreator(); 
     Product product = creator.createProduct(ConcreteProduct1. class );
     /** 
     *继续业务处理 
     */ 
  
}

改通用代码是一个比较实用、易扩展的框架,读者可以根据实际项目需要进行扩展。

希望本文所述对大家Java程序设计有所帮助。

 

  上一篇文章(http://www.cnblogs.com/liaoweipeng/p/5768197.html)讲了简单工厂模式,但是简单工厂模式存在一定的问题,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包-开放原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

 

三:抽象工厂模式

 

抽象工厂模式的概念

  抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。(百度百科)

抽象工厂模式的UML图

  

抽象工厂模式的代码

  我们接着简单工厂模式的例子继续讲解抽象工厂模式,如果在简单工厂模式中需要增加一种不男不女的人,就需要修改工厂类中的生成方法了,虽然可以实现我们需要的结果,但是违背了java的开放-闭包的原则。我们根据前面的例子做一改造。

/**
 * This is factory patter package
 */
package com.roc.factory;

/**
 * 产品的抽象接口  人类
 * @author liaowp
 *
 */
public interface Human {
    
    public void say();

}
/**
* This is factory patter package
*/
package com.roc.factory;

/**
* man  男人
*
@author liaowp
*
*/
public class Man implements Human {

   
/* say method
     * @see com.roc.factory.Human#say()
    
*/
    @Override
   
public void say() {
        System.out.println(
"男人" );
    }

}
/**
 * This is factory patter package
 */
package com.roc.factory;

/**女人
 * @author liaowp
 *
 */
public class Woman implements Human {

    /* say method
     * @see com.roc.factory.Human#say()
     */
    @Override
    public void say() {
        System.out.println("女人");
    }

}

前面的代码是一样的,现在我们需要为一种人创建一个工厂类,既然每一个人都有自己的工厂类,那是不是可以抽一个类呢,对的,我们就抽出一个工厂接口来。

package com.roc.factory;
/**
 * 工厂接口类
 * @author liaowp
 *
 */
public interface Factory {
    
    public Human crateMan();
    
}创造男人的工厂类
package com.roc.factory;
/**
 * 创造男人工厂类
 * @author liaowp
 *
 */
public class ManFactory implements Factory{

    public Human crateMan() {
        return new Man();
    }

}

创造女人的工厂类

package com.roc.factory;
/**
 * 创造女人工厂类
 * @author liaowp
 *
 */
public class WomanFactory implements Factory{

    @Override
    public Human crateMan() {
        // TODO Auto-generated method stub
        return new Woman();
    }

}

客户端类

package com.roc.factory;
/**
 * 抽象工厂测试
 * @author liaowp
 *
 */
public class Client {
    public static void main(String[] args) {    
        Factory factory=new ManFactory();
        Human  man2=factory.crateMan();
        man2.say();
        
    }
}

  改造完成,经过我这么一改造,你现在知道怎么增加创造不男不女的人吗?这样一改造你需要增加任何的类型都只需要增加一个工厂类,一个产品类。然后在客户端写出新的调用。完全符合了java的开发与闭包原则。

应用场景  

  第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
  第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值