原型模式知识汇总

原型模式

原型模式属于设计模式中的创建型

什么是原型模式

使用原型实例指定要创建对象的类型,并通过复制这个原型来创建新对象。也就是指派一个类的实例来作为未来所有实例的生成器。

原型模式的原理与应用

当对象初始化开销很大,并且初始化参数的变化不大时,原型非常有用。在这种情况下,原型可以避免昂贵的“从头创建”,并支持廉价地克隆预初始化的原型。原型模式在其他创建模式中是独一无二的,因为它不需要类而只需要对象。

为什么对象的初始化开销很大。

实际上,在创建对象的过程中包含的申请内存、给成员变量赋值这一过程,本身并不会花费太多时间,或者说对于大部分业务系统来说,这点时间完全是可以忽略的。应用一个复杂的模式,只得到一点点的性能提升,这就是所谓的过度设计,得不偿失。

但是,如果对象中的数据需要经过复杂的计算才能得到(比如排序、计算哈希值),或者需要从RPC、网络、数据库、文件系统等非常慢速的IO中读取,这种情况下,我们就可以利用原型模式,从其他已有对象中直接拷贝得到,而不用每次在创建新对象的时候,都重复执行这些耗时的操作。

深拷贝和浅拷贝

在使用原型模式克隆对象时,根据其成员对象是否也克隆,原型模式可以分为两种形式:深拷贝 和 浅拷贝 。

深拷贝和浅拷贝的区别

  1. 浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象
  2. 而深拷贝得到的是一份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间。

如果要拷贝的对象是不可变对象,浅拷贝共享不可变对象是没问题的,但对于可变对象来说,浅拷贝得到的对象和原始对象会共享部分数据,就有可能出现数据被修改的风险,也就变得复杂多了。如果没有充分的理由,不要为了一点点的性能提升而使用浅拷贝。

原型模式案例 1

用抽象工厂存储一组原型,从中克隆返回产品对象

interface Person {
    Person clone();
}

class Tom implements Person {
    private final String NAME = "Tom";

    @Override
    public Person clone() {
        return new Tom();
    }

    @Override
    public String toString() {
        return NAME;
    }
}

class Dick implements Person {
    private final String NAME = "Dick";

    @Override
    public Person clone() {
        return new Dick();
    }

    @Override
    public String toString() {
        return NAME;
    }
}

class Harry implements Person {
    private final String NAME = "Harry";

    @Override
    public Person clone() {
        return new Harry();
    }

    @Override
    public String toString() {
        return NAME;
    }
}

class Factory {
    private static final Map<String, Person> prototypes = new HashMap<>();

    static {
        prototypes.put("tom", new Tom());
        prototypes.put("dick", new Dick());
        prototypes.put("harry", new Harry());
    }

    public static Person getPrototype(String type) {
        try {
            return prototypes.get(type).clone();
        } catch (NullPointerException ex) {
            System.out.println("Prototype with name: " + type + ", doesn't exist");
            return null;
        }
    }
}

public class PrototypeFactory {
    public static void main(String[] args) {
        if (args.length > 0) {
            for (String type : args) {
                Person prototype = Factory.getPrototype(type);
                if (prototype != null) {
                    System.out.println(prototype);
                }
            }
        } else {
            System.out.println("Run again with arguments of command string ");
        }
    }
}

Output

>java PrototypeFactory tom dick jack

Tom
Dick
Prototype with name: jack, doesn't exist

原型模式案例 2

  1. 约定一个具有克隆属性的实体
  2. 设计一个具有注册功能的类来缓存原型对象
  3. 用一个方法来填充注册数据
  4. 注册类有一个方法能够根据传入的类型找到对应的对象并调用克隆方法
  5. 所有的类都实现克隆方法。
  6. 客户端通过克隆而不通过new来创建对象
// 1.约定一个具有克隆属性的实体
interface Prototype {
    Prototype clone();
    String getName();
    void execute();
}

class PrototypeModule {
    // 2.设计一个具有注册功能的类来缓存原型对象
    private static List<Prototype> prototypes = new ArrayList<>();


    public static void addPrototype(Prototype p) {
        prototypes.add(p);
    }

    public static Prototype createPrototype(String name) {
        // 4.注册类有一个方法能够根据传入的类型找到对应的对象并调用克隆方法
        for (Prototype p : prototypes) {
            if (p.getName().equals(name)) {
                return p.clone();
            }
        }
        System.out.println(name + ": doesn't exist");
        return null;
    }
}

// 5.所有的类都实现克隆方法。
class PrototypeAlpha implements Prototype {
    private String name = "AlphaVersion";

    @Override
    public Prototype clone() {
        return new PrototypeAlpha();
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void execute() {
        System.out.println(name + ": does something");
    }
}

class PrototypeBeta implements Prototype {
    private String name = "BetaVersion";

    @Override
    public Prototype clone() {
        return new PrototypeBeta();
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void execute() {
        System.out.println(name + ": does something");
    }
}

class ReleasePrototype implements Prototype {
    private String name = "ReleaseCandidate";
    @Override
    public Prototype clone() {
        return new ReleasePrototype();
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void execute() {
        System.out.println(name + ": does real work");
    }
}

public class PrototypeDemo {
    public static void main(String[] args) {
        if (args.length > 0) {
            initializePrototypes();
            List<Prototype> prototypes = new ArrayList<>();
            // 6.客户端通过克隆而不通过new来创建对象
            for (String protoName : args) {
                Prototype prototype = PrototypeModule.createPrototype(protoName);
                if (prototype != null) {
                    prototypes.add(prototype);
                }
            }
            for (Prototype p : prototypes) {
                p.execute();
            }
        } else {
            System.out.println("Run again with arguments of command string ");
        }
    }

    // 3.用一个方法来填充注册数据
    public static void initializePrototypes() {
        PrototypeModule.addPrototype(new PrototypeAlpha());
        PrototypeModule.addPrototype(new PrototypeBeta());
        PrototypeModule.addPrototype(new ReleasePrototype());
    }
}

Output

>java PrototypeDemo Garbage AlphaVersion BetaVersion Nothing ReleaseCandidate

Garbage: doesn't exist
Nothing: doesn't exist
AlphaVersion: does something
BetaVersion: does something
ReleaseCandidate: does real work
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值