设计模式-创建模式(Creational Pattern)

创建模式(Creational Pattern)是对类的实例化过程的抽象化。
创建模式分为类创建模式对象的创建模式两种。

简单工厂模式(Simple Factory)
静态工厂方法模式(Static Factory Method Pattern)

工厂方法模式(Factory Method)
多态性工厂模式(Polymorphic Factory)
虚拟构造子模式(Virtual Constructor)

抽象工厂模式(Abstract Factory)
工具箱模式(Kit/Toolkit)

单例模式(Singleton)

多例模式(Multition Pattern)

建造模式(Builder)

原始模型模式(Protorype)

简单工厂模式

类图

简单工厂模式的结构
/**
 * <b>Description:</b> 抽象产品Concrete Product <br>
 */
public interface Fruit {
    void grow();

    void harvest();

    void plant();
}
/**
 * <b>Description:</b> 具体产品Product <br>
 */
public class Apple implements Fruit {
    private int treeAge;
    @Override
    public void grow() {
        Log.i("","Apple is growing...");
    }

    @Override
    public void harvest() {
        Log.i("","Apple has been harvested.");
    }

    @Override
    public void plant() {
        Log.i("","Apple  has been planted.");
    }

    public int getTreeAge() {
        return treeAge;
    }

    public void setTreeAge(int treeAge) {
        this.treeAge = treeAge;
    }
}
/**
 * <b>Description:</b> 具体产品Product <br>
 */
public class Grape implements Fruit {

    private boolean seedless;

    @Override
    public void grow() {
        Log.i("", "Grape is growing...");
    }

    @Override
    public void harvest() {
        Log.i("", "Grape has been harvested.");
    }

    @Override
    public void plant() {
        Log.i("", "Grape  has been planted.");
    }

    public boolean isSeedless() {
        return seedless;
    }

    public void setSeedless(boolean seedless) {
        this.seedless = seedless;
    }
}
/**
 * <b>Description:</b> 具体产品Product <br>
 */
public class Strawberry implements Fruit {
    @Override
    public void grow() {
        Log.i("", "Apple is growing...");
    }

    @Override
    public void harvest() {
        Log.i("", "Apple has been harvested.");
    }

    @Override
    public void plant() {
        Log.i("", "Apple  has been planted.");
    }
}
/**
 * <b>Description:</b> 工厂类Creator(上帝类God Class) <br>
 * 模式的核心。含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例。
 */
public class FruitGardener {

    public static Fruit factory(String which) throws BadFruitException {
        if (which.equalsIgnoreCase("apple")) {
            return new Apple();
        }
        if (which.equalsIgnoreCase("strawberry")) {
            return new Strawberry();

        }
        if (which.equalsIgnoreCase("grape")) {
            return new Grape();
        } else {
            throw new BadFruitException("");
        }
    }
}
/**
 * <b>Description:</b> 异常类 <br>
 */
public class BadFruitException extends Exception {

    public BadFruitException(String message) {
        super(message);
    }
}

工厂方法模式

类图

工厂方法模式的结构
/**
 * <b>Description:</b> 抽象工厂Creator <br>
 * 模式的核心。
 */
public interface FruitGardener {
    Fruit factory();
}
/**
 * <b>Description:</b> 具体工厂Concrete Creator <br>
 */
public class AppleGardener implements FruitGardener {
    @Override
    public Fruit factory() {
        return new Apple();
    }
}
/**
 * <b>Description:</b> 具体工厂Concrete Creator <br>
 */
public class GrapeGardener implements FruitGardener {
    @Override
    public Fruit factory() {
        return new Grape();
    }
}
/**
 * <b>Description:</b> 具体工厂Concrete Creator <br>
 */
public class StrawberryGardener implements FruitGardener {
    @Override
    public Fruit factory() {
        return new Strawberry();
    }
}

抽象工厂模式

类图

抽象工厂模式的结构
/**
 * <b>Description:</b> 抽象产品 <br>
 */
public interface Fruit {
}
/**
 * <b>Description:</b> 具体产品类 <br>
 */
public class NorthernFruit implements Fruit {
    private String name;

    public NorthernFruit(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * <b>Description:</b> 具体产品类 <br>
 */
public class TropicalFruit implements Fruit {

    private String name;

    public TropicalFruit(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * <b>Description:</b> 抽象产品 <br>
 */
public interface Veggie {
}
/**
 * <b>Description:</b> 具体产品类 <br>
 */
public class NorthernVeggie implements Veggie {
    
    private String name;

    public NorthernVeggie(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * <b>Description:</b> 具体产品类 <br>
 */
public class TropicalVeggie implements Veggie {
    private String name;

    public TropicalVeggie(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/**
 * <b>Description:</b> 抽象工厂 <br>
 * 模式的核心。
 * 1.一个系统不应当依赖于产品类的实例如何被创建、组合和表达的细节。(所有工厂模式)
 * 2.这个系统的产品有多余一个的产品族,而系统只消费其中某一个产品族的产品。(原始用意)
 * 3.同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
 * 4.系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
 */
public interface Gardener {
    Fruit createFruit(String name);

    Veggie createVeggie(String name);
}
/**
 * <b>Description:</b> 具体工厂类 <br>
 */
public class NorthernGardener implements Gardener {


    @Override
    public Fruit createFruit(String name) {
        return new NorthernFruit(name);
    }

    @Override
    public Veggie createVeggie(String name) {
        return new NorthernVeggie(name);
    }
}
/**
 * <b>Description:</b> 具体工厂类 <br>
 */
public class TropicalGardener implements Gardener{
    @Override
    public Fruit createFruit(String name) {
        return new TropicalFruit(name);
    }

    @Override
    public Veggie createVeggie(String name) {
        return new TropicalVeggie(name);
    }
}

单例模式

特点

1.单例类只能有一个实例。
2.单例类必须自己创建自己的唯一实例。
3.单例类必须给所有其他对象提供这一实例。
虽然单例模式中的单例类被限定只能有一个实例,但是单例模式和单例类可以很容易被推广到任意且有有限多个实例的情况,这时候称它为多例模式和多例类。

饿汉式单例类
懒汉式单例类
登记式单例类

饿汉式单例类

/**
 * <b>Description:</b> 饿汉式单例类 <br>
 * 饿汉式单例类在自己被加载时将自己实例化。
 * 即便加载器是静态的,在饿汉式单例类加载时仍会将自己实例化。
 * 单从资源利用率角度来讲,这个比懒汉式单例类稍差些。
 * 从速度和反应时间角度来讲,则比懒汉式单例类稍好些。
 * <p>
 * 不可继承
 */
public class EagerSingleton {

    private static final EagerSingleton mInstance = new EagerSingleton();

    /**
     * 私有的默认构造子
     */
    private EagerSingleton() {
    }

    /**
     * 静态工厂方法
     *
     * @return
     */
    public static EagerSingleton getInstance() {
        return mInstance;
    }
}

懒汉式单例类

/**
 * <b>Description:</b> 懒汉式单例类 <br>
 * 懒汉式单例类在实例化时,必须处理好在多个线程同时抽次引用此类时访问限制问题,特别是当单例类作为资源控制器在实例化时必然涉及资源初始化,而资源初始化很有可能耗费时间。
 * 这意味着出现多线程同时首次引用此类的几率变得较大。
 * <p>
 * 不可继承
 */
public class LazySingleton {

    private static LazySingleton mInstance = null;

    /**
     * 私有的默认构造子,保证外界无法直接实例化
     */
    private LazySingleton() {
    }

    /**
     * 静态工厂方法,返还此类的唯一实例
     *
     * @return
     */
    synchronized public static LazySingleton getInstance() {
        if (mInstance == null) {
            mInstance = new LazySingleton();
        }
        return mInstance;
    }
}

登记式单例类

/**
 * <b>Description:</b> 登记式单例类 <br>
 * 饿汉式
 * 可继承
 */
public class RegSingleton {
    static private HashMap mRegistry = new HashMap();

    static {
        RegSingleton x = new RegSingleton();
        mRegistry.put(x.getClass().getName(), x);
    }

    /**
     * 保护的默认构造子
     */
    protected RegSingleton() {

    }

    /**
     * 静态工厂方法,返还此类的唯一实例
     *
     * @param name
     * @return
     */
    static public RegSingleton getInstance(String name) {
        if (name == null) {
            name = "pr.tongson.pattern.Singleton.RegSingleton";
        }
        if (mRegistry.get(name) == null) {
            try {
                mRegistry.put(name, Class.forName(name).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }


        return (RegSingleton) mRegistry.get(name);
    }

    /**
     * 一些示意性的商业方法
     *
     * @return
     */
    public String about() {
        return "Hello, I am RegSigleton.";
    }
}
/**
 * <b>Description:</b> 登记式单例类 <br>
 * 懒汉式
 * 子类
 */
public class RegSigletonChild extends RegSingleton {

    public RegSigletonChild() {
    }

    static public RegSigletonChild getInstance() {
        return (RegSigletonChild) RegSingleton.getInstance("pr.tongson.pattern.Singleton.RegSigletonChild");
    }

    /**
     * 一些示意性的商业方法
     *
     * @return
     */
    @Override
    public String about() {
        return "Hello, I am RegSigletonChild.";
    }
}

在什么情况下使用单例模式

必要条件:在一个系统要求一个类只有一个实例时才应当使用单例模式。

有状态的单例类

User类

没有状态的单例类(提供工具性函数的对象)

Uitl类

属性类

多例模式

多例模式中的多例类可以有多个实例,而且多例类必须自己创建、管理自己的实例,并向外界提供自己的实例。
所谓多例模式实际上就是单例模式的自然推广。

特点:

1.多例类可有多个实例。
2.多例类必须自己创建、管理自己的实例,并向外界提供自己的实例。

public class Die {
    private static Die die1 = new Die();
    private static Die die2 = new Die();

    /**
     * 私有的构造子保证外界无法直接将此类实例化
     */
    private Die() {
    }

    /**
     * 工厂方法
     *
     * @param whichOne
     * @return
     */
    public static Die getInstance(int whichOne) {
        if (whichOne == 1) {
            return die1;
        } else {
            return die2;
        }
    }

    /**
     * 掷骰子,返回一个在1~6之间的随机数
     *
     * @return
     */
    public synchronized int dice() {
        Date date = new Date();
        Random random = new Random(date.getTime());
        int value = random.nextInt();
        value = Math.abs(value);
        value = value % 6;
        value += 1;
        return value;
    }
}
public class Client {
    private static Die die1, die2;

    public static void main(String[] args) {
        die1 = Die.getInstance(1);
        die2 = Die.getInstance(2);
        die1.dice();
        die2.dice();
    }
}

无上限多例模式

有状态的和没有状态的多例类

Lingual Resource

序列键生成器

没有数据库的情况
有数据库的情况
键值的缓存方案
有缓存的多序列键生成器

建造者模式

类图

构建者模式的结构
/**
 * <b>Description:</b> 产品 <br>
 * 复杂对象
 * 一般来说,每有一个产品类,就有一个相应的具体建造类。
 * 这些产品应当有一样数目的零件,而每有一个零件就相当地在所有的建造者角色里有一个构造方法。
 */
public class Product {
    //Anything pertaining to this product
}
/**
 * <b>Description:</b> 抽象建造者 <br>
 * 给出一个抽象接口,以规范产品对象的各个组成成分的建造。
 * 一般而言,此接口独立于应用程序的商业逻辑。
 */
abstract public class Builder {
    /**
     * 产品零件建造方法
     */
    public abstract void buildPart1();

    /**
     * 产品零件建造方法
     */
    public abstract void buildPart2();

    /**
     * 产品返还方法
     *
     * @return
     */
    public abstract Product retrieveResult();
}
/**
 * <b>Description:</b> 具体建造者 <br>
 * 创建产品实例
 */
public class ConcreteBuilder extends Builder {
    private Product mProduct = new Product();

    /**
     * 产品零件建造方法
     */
    @Override
    public void buildPart1() {
        //build the first part of the product
    }

    /**
     * 产品零件建造方法
     */
    @Override
    public void buildPart2() {
        //build the second part of the product
    }

    /**
     * 产品返还方法
     *
     * @return
     */
    @Override
    public Product retrieveResult() {
        return mProduct;
    }
}
/**
 * <b>Description:</b> 导演者 <br>
 * 调用具体建造者以创建产品对象。
 */
public class Director {
    private Builder mBuilder;

    /**
     * 产品构造方法,负责调用各个零件构造方法
     */
    public void construct() {
        mBuilder = new ConcreteBuilder();
        mBuilder.buildPart1();
        mBuilder.buildPart2();
        mBuilder.retrieveResult();
        //continue with othor code
    }
}

空的零件建造方法(ConcreteBuilder)

省略抽象建造者角色(Builder)

省略导演者角色(Director)

过渡到模板(Template)方法模式

合并建造者角色和产品角色

建造者角色可以有多个产品构造方法

在什么情况下使用建造模式

在以下情况下应当使用建造模式:
1.需要生成的产品对象有复杂的内部结构。每一个内部成分本身可以是对象,也可以仅仅是一个对象(即产品对象)的一个组成成分。
2.需要生成的产品对象的属性相互依赖。建造者模式可以强制实行一种分步骤进行的建造过程,因此,如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值,使用建造模式便是一个很好的设计思想。
有时产品对象的属性并无彼此依赖的关系,但是在产品的属性没有确定之前,产品对象不能使用。这时产品对象的实例化,属性的赋值和使用仍然是分步骤进行的。因此,创建模式仍然有意义。
3.在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。

同时,使用建造模式主要有以下的效果:

  • 建造模式的使用使得产品的内部表象可以独立地变化。使用建造模式可以使客户端不必知道产品内部组成的细节。
  • 每一个Builder 都相对独立,而与其他的Builder无关。
  • 模式所建造的最终产品更易于控制。

原始模型模式

简单形式

/**
 * <b>Description:</b> 抽象原型 <br>
 * 给出所有的具体原型类所需的接口
 */
public interface Prototype extends Cloneable {
    Prototype clone();
}

/**
 * <b>Description:</b> 具体原型 <br>
 * 被复制的对象
 * 需要实现抽象的原型角色所要求的接口。
 */
public class ConcretePrototype implements Prototype {
    /**
     * 克隆方法
     *
     * @return
     */
    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

/**
 * <b>Description:</b> 客户 <br>
 * 提出创建对象的请求
 */
public class Client {
    private Prototype mPrototype;

    public void operation(Prototype example) {
        Prototype copytype = example.clone();
    }
}

登记形式

/**
 * <b>Description:</b> 原型管理器 <br>
 * 记录每一个被创建的对象
 */
public class PrototypeManager {
    private Vector objects = new Vector();

    /**
     * 聚集管理方法:增加一个新的对象
     *
     * @param object
     */
    public void add(Prototype object) {
        objects.add(object);
    }

    /**
     * 聚集管理方法:取出聚集中的一个对象
     *
     * @param i
     * @return
     */
    public Prototype get(int i) {
        return (Prototype) objects.get(i);
    }

    /**
     * 聚集管理方法:给出聚集的大小
     *
     * @return
     */
    public int getSize() {
        return objects.size();
    }
}

/**
 * <b>Description:</b> 客户端 <br>
 * 客户端类向管理员提出创建对象的请求
 */
public class Client {
    private PrototypeManager mPrototypeManager;
    private Prototype mPrototype;

    public void registerPrototype() {
        mPrototype = new ConcretePrototype();
        Prototype copyType = (Prototype) mPrototype.clone();
        mPrototypeManager.add(copyType);
    }
}

浅复制

有一些不同

深复制

完全相同,但也不是同一个对象,需要java.io.Serializable

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容