设计模式-----工厂模式

来源:互联网 发布:国行a1533支持什么网络 编辑:程序博客网 时间:2024/05/18 00:33

工厂模式

工厂方法模式的定义

    定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

这里写图片描述

在工厂模式中,其中Product负责抽象具体对象的共性,实现对事务最抽象的定义。Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂 ConcreteCreator完成的。

工厂类的实现

我们来看一个女娲造人的类图:

这里写图片描述

其中AbstractHumanFactory是一个抽象类:

public abstract class AbstractHumanFactory {     public abstract <T extends Human> T createHuman(Class<T> c); }

我们可以看到在抽象方法中接收Human的子类,并返回对应的Human的子类。

Human为接口,提供人类的规范:

public interface Human {         //每个人种的皮肤都有相应的颜色         public void getColor();         //人类会说话         public void talk(); }

白种人、黄种人、黑种人分别实现Human接口,提供相关的实现。

具体的工厂类,为HumanFactory 继承自AbstractHumanFactory 并实现抽象方法。

public class HumanFactory extends AbstractHumanFactory {         public <T extends Human> T createHuman(Class<T> c){               //定义一个生产的人种                 Human human=null;                 try {                          //产生一个人种                          human = (T)Class.forName(c.getName()).newInstance();             } catch (Exception e) {                  System.out.println("人种生成错误!");                 }             return (T)human; }

在createHuman方法中接收Human的子类对象类,采用反射的方法创建对象的实例。

这样一个简单的工厂类就被创建出来,我们采用工厂类,可以每次创建出不同的对象。并在抽象的过程中,采用抽象类依赖于接口类,介绍了类之间的耦合,从而工厂类不再耦合具体对象,可以创建出不同Human的子类对象。

工厂模式的优点

  1. 具有良好的封装,调用者只需要知道类名即可,不需要知道对象创建的具体过程,降低模块之间的耦合
  2. 工厂方法的拓展性比较强,比如我们在上面再加一个BrownHuman类,工厂类不需要做任何修改。
  3. 屏蔽类的创建过程,只关心产品的上层接口,只要接口保持不变系统中的其他模块就不需要发生变化。
  4. 典型的解耦框架,高层模块负责产品的抽象,其他实现类不需要关心,符合符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类。

工厂模式的使用场景

工厂模式就是new对象的一个替代品,所有在生成对象的地方都可以用,但是要考虑编码的复杂性。
需要可扩展,灵活的框架时,比如在发送邮件的时候有三个协议POP3、IMAP、HTTP,那么我们可以将他们抽象为一个接口,然后三个协议实现接口,定义工厂类,然后根据传入的协议信息返回不同协议的实现。这样设计比如我们邮件服务器提供了WebService接口,我们只需要在增加一个产品类实现接口接口。

工厂模式的拓展

  • 缩小为简单工厂模式

    简单模式也称为静态工厂模式,比如在上面生产人类的实例上面,我们可以把生产工厂的实现,去掉AbstractHumanFactory类,并将具体实现改为static方法,这样也可,但是这样做工厂类的扩展就比较困难,不符合开闭原则.

  • 升级为多个工厂类

    如果我们将所有的产品类都放到一个工厂方法中进行初始化,或许会导致代码的结构不清晰,。例如,一个产品类有5 个具体实现,每个实现类的初始化(不仅仅是new,初始化包括new一个对象,并对对象设置一定的初始值)方法都不相同,如果写在一个工厂方法中,势必会导致该方法巨大无比。

    对此我们可以将工厂方法进行细化,每个工厂发送负责一类对象的创建。
    这里写图片描述

至此,每个人种都有一个单独的工厂类,这种方式每个工厂创建的职责非常清晰,而且结构简单,但是可扩展性,降低比如我们在添加BrownHuman类,那么我们不仅仅要实现底层的实现,而且还要在编码一个具体BrownHuman的工厂类。

在复杂的应用中,大多采用多工厂的方法,然后在增加一个协调类,将各个子工厂进行封装,然后提供统一的外部接口。

  • 替换单例模式

采用工厂方法替换单例模式:

我们将单例的构造方法私有化。

public class Singleton {        //不允许通过new产生一个对象     private Singleton(){     }     public void doSomething(){             //业务处理     } }

然后在工厂模式中,利用反射创建单例。

public class SingletonFactory {     private static Singleton singleton;     static{              try {                    Class cl= Class.forName(Singleton.class.getName());                    //获得无参构造                    Constructor constructor=cl.getDeclaredConstructor();                    //设置无参构造是可访问的                    constructor.setAccessible(true);                    //产生一个实例对象                    singleton = (Singleton)constructor.newInstance();             } catch (Exception e) {                    //异常处理             }     }     public static Singleton getSingleton(){             return singleton;       } }

当工厂加载到JVM时,触发静态代码块,然后利用反射将对象的构造方法设置为可访问的,然后创建对象实例。

该框架仍可以进行扩展,任何单例都可以在此工厂方法中进行扩展。

  • 延迟初始化

延迟初始化是指,一个对象被消费完毕之后,并不立即释放,工厂类保持初始状态,等待再次被调用。

这里写图片描述

ProductFactory负责产品类对象的创建工作,并且通过prMap变量产生一个缓存,对需要 再次被重用的对象保留。

延迟加载同样是可以拓展的,比如限制对象实例的最大数量,我们可以通过判断Map的size进行判断。

延迟加载还可以用在对象初始化比较复杂的情况下,例如硬件访问,涉及多方面的交互,则可以通过延迟加载降低对象的产生和销毁带来的复杂性

0 0
原创粉丝点击