java模式笔记 (三)—— 创建模式

类的创建模式:使用继承关系,把类的创建延迟到子类

对象的创建模式:对象的创建过程动态地委派给另一个对象

使用工厂的原因

1.  静态工厂具有名字

    i.  对于两个构造函数,如果参数类型和个数相同,则只能使用不同的顺序进行区分,而使用工厂函数可以为这两个构造函数指明不同的名称

    ii. 如果有多个构造函数,可考虑用静态工厂方法替换

2.  可复用已有对象

    i.  当系统需要该类的N或1个实例,如果使用构造函数,则每次调用都会创建一个实例,可通过单例或多例模式重用已有实例

3.  返回原类型的子类型对象

    i.  对于一个继承体系,在基类中声明静态工厂方法,根据type返回不同的子类实例,且该子类为package 或 private,可以向客户端隐藏子类。

4. 使用工厂模式的 拷贝函数,代替clone

    具体原因参考 effective java

简单工厂

作用:

       由一个工厂类决定创建出哪一种产品的实例,对客户端隐藏具体子类的实例化

        用于 产品类结构层次简单,修改不频繁

角色:

       IProduct:作为产品接口

       ProductA 和ProductB 作为具体的产品

       SimpleFactory 使用方法 static IProduct createProduct(String type) 根据type创建产品,可以有多个create方法

       Client:使用产品 IProduct

优缺点:

1.     创建产品的责任从客户端移交给了工厂类,客户端仅使用;

2.     增加新的产品需要修改工厂类,容易变成fatmethod;产品类的等级结构不能反应到工厂类中;静态方法无法被继承

变形:

        简单工厂可以和抽象产品类合并,根据type,返回具体的子类,实例如 DateFormat.getTimeInstance();  

        简单工厂、抽象产品和具体类合并  就快退化成了单例模式

        对于非 简单工厂 支持的类型,可以抛出BadTypeException 异常

工厂方法

       定义工厂接口 Creator,将具体创建工作放到子类 ConcreteCreator 中

作用:     

       当产品类具有较复杂的结构,如产品树高度大于2,有多个抽象类,则将工厂也按产品类形成类似结构,只有具体工厂类完成产品的创建

角色:

        Product:框架包内,产品接口,构造函数非公有,规定应有的方法。

        Creator:框架包内,生产者接口,定义public Produt  create()

        ConcreteProduct:实际处理包内,构造函数非公有,具体产品

        ConcreteCreator:实际处理包内,实现create方法。

优缺点:

       对简单工厂 抽象为 Creator和ConcreteCreator,当加入新的产品,只需要增加工厂和产品类,不需要修改抽象类

       支持开闭原则

注意:

        在client中有Creatortc=new 具体工厂()

      Creator中工厂函数返回为抽象产品类 Product

      对简单工厂模式的SimpleCreator 执行重构 :replace switch with polysim 后得到工厂模式

和其他模式关系:

       工厂模式常和模板模式结合使用:模板模式将某一顶级行为分解为多个创建行为,而具体的创建由子类来实现

       享元模式使用了带有循环逻辑的工厂方法

       备忘录模式中的多例可以使用工厂方法来创建

实例:

       java中的Collection 和Iterator 的关系       

抽象工厂模式

       不必指定产品的类型,就可以创建多个平行的产品族中的产品对象

作用:

       有多个产品体系,这些产品体系有类似的结构且相互关联,如windows和macOS的显示组件。

       解决:具体工厂类创建产品体系间某一类型的具体产品,如使用不同的方法创建不同操作系统的menu。

角色:

        AbstractProduct:规定抽象零件的接口,有多种类,每种作为不同产品体系的顶层类,如 WindowsUI, LinuxUI 。

        AbstractFactory: 接口,定义创建产品族的方法,有几个产品族就有几个方法,每个方法返回某一AbstractProduct。有两个函数 一个创建 WindowUI, 一个创建LinuxUI 对象    简单工厂的静态方法返回具体的工厂

        Client:调用AbstractFactory实例,只使用AbstractFactory和AbstractProduct接口

        ConcreteProduct:实现了AbstractProduct

        ConcreteFactory:实现AbstractFactory中方法,如MenuFactory 实现AbstractFactory,有两个函数 一个创建 WindowUI, 一个创建LinuxUI 对象

应用场景:

       有多于一个的产品族(产品族和体系结构可构造二维的相图),系统一次只消费一族的产品

实例:

       创建不同操作系统中的视图        

和其他模式关系:

工厂模式:针对一个产品等级结构,而抽象工厂针对多个平行的产品等级结构;

简单工厂模式:抽象工厂有静态函数返回具体工厂实例:隐藏具体工厂类

单例模式:具体工厂类有静态函数就变成单例模式

桥梁模式:抽象工厂模式为桥梁模式提供某一等级结构的创建 

单例模式

作用:

    创建在程序中只有一个的对象,如充当计数器的类对象。

   单例类因为私有构造函数,不能被继承

与静态函数类的区别:

    单例类可扩展为N例类

    单例方便mock,静态类比较麻烦

    单例可继承抽象类和实现接口,静态类不行

角色:

    Singleton:创建单例的类,包含静态函数getInstance(),私有构造函数,本类的对象

应用场景:

    单例模式:整个系统只有一个实例

    多例模式:有多种实例,但每种实例只有一个

    对象创建后直到环境重启一直存在

注意:

     

     在使用EJB RMI和JINI系统中 、一个JVM有多个类加载器的情况下不要使用 带状态的单例

     最简单的方法:静态成员变量private static Singleton instance = new Singleton(); 这样在类第一次加载时,就会创建单例,如果创建非常消耗资源,而始终没有使用就浪费了,可以使用懒加载改进,但懒加载在多线程环境下会有问题,singleton可能会出现多个实例?  解决的办法很简单,加个同步修饰符:public static synchronized Singleton getInstance(). 这样就保证了线程的安全性,但这样要求每次调用getInstance() 获得单例锁,但其实在创建完以后就没有必要了,解决方案是 double-check (两次判断instance==null,对第二次synchronized ),如下所示:

if(uniqueInstance == null){  
            synchronized(Singleton.class){    //进入同步区域  
                if(uniqueInstance == null){     //在检查一次,如果为null,则创建  
                    uniqueInstance  = new Singleton();  
                }  
            }  
        }  


    但在JVM中执行时,分配内存和创建实例是分开的还会有问题,考虑使用内部类

public class Singleton{      
    private Singleton(){      
        …      
    }      
    private static class SingletonContainer{      
        private static Singleton instance = new Singleton();      
    }      
    public static Singleton getInstance(){      
        return SingletonContainer.instance;      
    }      
}     

生成器模式

作用:

        积木式构造更复杂的对象。

优点:

        1. 每一个具体的builder都相互独立,可以很方便扩展ConcreteBuilder

        2. Client不知道产品内部组成的细节

应用场景:

        1.   要构造的对象比较复杂。

        2 .  构造对象的属性有顺序(在director中指定构造顺序)

        3.   构造中使用到系统中的其他一些对象,而这些对象在new 中不易得到, set传入。

角色:

        Builder:接口,定义零件建造方法,有两种方法,零件构建 void createPart;获取产品 getProduct. 

        ConcreteBuilder:实现类,构造具体的零件,提供具体的产品

      ConcretePart:构建对象的零件,由ConcreteBuilder新建,只在本类可见

        Director:以特定顺序调用Builder方法生产产品, 使用Builder.getProduct获取产品

        Client:创建Director和ConcreteBuilder对象,调用direcotr.construct()创建,调用ConcreteBuilder.getProduct获取产品 。

说明:

      Client 找到Director和ConcreteBuilder要创建产品;Director负责使用零件组装产品,所以需要定义需要零件的类型和个数;ConcreteBuilder根据规格 Builder ,创建需要的零件。

       Product将属性的建造外部化到对象Builder和ConcreteBuilder中,并通过Director对这些属性的顺序进行协调。

       在实际中,Client中的创建放在springxml中进行,则client只要调用 director.construct() 即可。

       有多少类产品,就有多少 ConcreteBuilder,这些类产品有一样数目的零件,  有多少种零件,Builder中就有多少建造方法。

       对于多个Product类,其本身可能没有太多的共有方法,但为了客户端方便访问,提供一个标识接口Product,客户端可使用向下转型进行使用

变形:

       去掉Builder:只有一个具体的构造者时(不建议)

       去掉Director: 将construct方法放在Builder中

       合并Builder和Product: 如果只有固定的零件时

注意事项:

    “谁知道哪个部分”相当重要

            Client知道Director和ConcreteBuidler,但不知道具体的构建过程

            Director 唯一知道的就是Builder类 ,但并不知道实际利用的是哪个ConcreteBuilder。

与其他模式关系

       抽象工厂:建造模式中的ConcretePart,可通过抽象工厂来得到

       策略模式:不同的具体策略类实现效果相同,而不同的ConcreteBuilder 创建的产品完全不一样

       合成模式:合成模式描述对象树的组织结构,建造模式描述对象树的生成过程

原型模式

作用:

   以一个对象为原型,产生出新的对象实例,实现clonable接口,使用Lang中的clone方法。

    是 接口+实现 和 javaClonable 接口的结合

优缺点:

    增加新的产品类,对其他内容无影响

    缺点是对每个类都要配备clone方法,如果该类引用了不支持Seariable对象,或者含有循环结构就麻烦了

角色 (简单形式):

    Prototype:要复制对象的接口,继承了Clonable接口(或者直接就是CLoneable接口)

    ConcretePrototype:实现接口,clone() 完成对象的拷贝

    Client: 使用Prototype.clone()完成对象的赋值

注意事项:

    调用java 对象clone方法,需要该对象实现Clonable 接口,建议同时实现equals(默认比较引用) 方法

    深拷贝的实现:对象实现Seriable接口,将对象写到流中,然后再从流中读出

与其他模式关系

    工厂模式:原型模式创建对象时,和对象的产品结构无关

    合成模式:经常一起使用,合成对象也是原型对象

    门面模式:原型模式的客户端可以起到门面对象的作用

    装饰模式:串行化用到的IO 中使用了装饰模式

你可能感兴趣的:(java模式笔记 (三)—— 创建模式)