Java版设计模式之【原型模式】

169 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

概述

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

角色

抽象原型:通常由接口或抽象类实现,给出所具有的具体原型类所需的接口。

具体原型:被复制的对象,必须实现抽象原型接口。

客户:提出创建对象的请求。

起因

小张:哥,有没有空呀?我这边又遇到难题了...

我:你小子,之前不少还跟我吹说没有你搞不定的嘛,这次又遇上什么问题了,我看看。

小张:就是这个对象,创建的时间太长了,我在循环里面创建起来太费时间了。

/**
 * 具体实例对象
 */
public class MonkeyKing {

    /**
     * 名称
     */
    private String name;
    /**
     * 别名
     */
    private String alias;
    /**
     * 对手
     */
    private String opponent;

    public MonkeyKing(String name) {
        // 模拟创建耗时
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.name = name;
    }
}
/**
 * 客户端
 */
public class PrototypePatternClient {
    static final String[] opponent = {"天兵", "天将"};
    public static void main(String[] args) {
        for(int i = 1; i <= 10; ++i){
            MonkeyKing client = new MonkeyKing("齐天大圣");
            client.setAlias("大圣分身" + i);
            client.setOpponent(opponent[(int) (System.currentTimeMillis() % 2)]);
            System.out.println(client.toString());
        }
    }
}

我:这样子耗时肯定长的呀,你这方法就相当于每次都需要等那块石头吸收满日月精华,然后孙悟空才横空出世。

我:你应该学学他后面的操作,拔下猴毛之后一吹,就变出很多分身出来,这样遇敌的时候才能及时迎敌。

模板

具体原型:实现Cloneable接口,重写clone方法。

/**
 * 实现 Cloneable 接口
 */
public class MonkeyKing implements Cloneable{

    /**
     * 名称
     */
    private String name;
    /**
     * 别名
     */
    private String alias;
    /**
     * 对手
     */
    private String opponent;

    /**
     * 克隆对象
     */
    @Override
    protected MonkeyKing clone() {
        System.out.println("拔下猴毛,吹毛成兵");
        MonkeyKing monkeyKing = null;
        try {
            monkeyKing = (MonkeyKing)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return monkeyKing;
    }

    public String getName() {
        return name;
    }

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

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public String getOpponent() {
        return opponent;
    }

    public void setOpponent(String opponent) {
        this.opponent = opponent;
    }

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

    @Override
    public String toString() {
        return "分身:【" + this.alias + "】找上了【" + this.opponent + "】做对手";
    }
}

客户端:获取对象。

public class PrototypePatternClient {
    static final String[] opponent = {"天兵", "天将"};
    public static void main(String[] args) {
        MonkeyKing monkeyKing = new MonkeyKing("齐天大圣");

        for(int i = 1; i <= 10; ++i){
            MonkeyKing mk = monkeyKing.clone();
            mk.setAlias("大圣分身" + i);
            mk.setOpponent(opponent[(int) (System.currentTimeMillis() % 2)]);
            System.out.println(mk.toString());
        }
    }
}

小结

优点

性能:原型模式是在内存二进制流的复制,要比直接new一个对象性能好,特别是在一个循环体内产生大量的对象时,原型模式可以更好的提现其特点。

减少约束:直接在内存中复制,可以绕开构造函数的约束,减少创建的限制与耗时,但在实际应用中需谨慎考虑。

适用场景

  • 在类初始化需要消耗非常多的资源(包括但不限于数据,硬件资源等)时,可以使用原型模式
  • 创建一个对象需要非常繁琐的数据或访问权限时,可以使用原型模式
  • 一个对象需要提供给多个修改者进行访问,而且各个修改者均可能对其进行修改时,可以使用原型模式