原型模式,一个无用的模式?

目录

一、简介

1、定义

2、使用场景

3、模式分析

4、优缺点

二、实现

1、UML类图

2、Prototype

3、ConcretePrototypeA

4、ConcretePrototypeB

5、PrototypeCache

6、Client_Prototype

三、原型模式分析

1、问题描述

 2、Person_Prototype

3、Cilent客户端

4、分析


一、简介

1、定义

原型模式就是从一个对象再创建另一个可定制的对象,而不需要知道任何创建的细节。

2、使用场景

 我们现在一般会使用new关键字指定类名生成类的实例(PS:我们以前使用java.lang.Cloneable的一个很大原因是使用new创建对象的速度相对来说会慢一些,随着JVM性能的提升,new的速度和Object的clone()方法的速度差不多了。)。

使用new关键字创建类的时候必须指定类名,但是在开发过程中也会有“在不指定类名的前提下生成实例”的需求。例如,在下面这些情况下,就需要根据现有的实例来生成新的实例。

1) 对象种类繁多,无法将他们整合到一个类的时候;

2) 难以根据类生成实例时;

3) 想解耦框架与生成的实例时。

如果想要让生成实例的框架不再依赖于具体的类,这时,不能指定类名来生成实例,而要事先“注册”一个“原型”实例,然后通过复制该实例来生成新的实例。

3、模式分析

在原型模式结构中定义了一个抽象原型类,所有的Java类都继承自java.lang.Object,而Object类提供一个clone()方法,可以将一个Java对象复制一份。因此在Java中可以直接使用Object提供的clone()方法来实现对象的克隆,Java语言中的原型模式实现很简单。

能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持复制。如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常。

注意: `java.lang.Cloneable 只是起到告诉程序可以调用clone方法的作用,它本身并没有定义任何方法。

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

4、优缺点

原型模式的优点:

  • 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过一个已有实例可以提高新实例的创建效率。
  • 可以动态增加或减少产品类。
  • 原型模式提供了简化的创建结构。
  • 可以使用深克隆的方式保存对象的状态。

原型模式的缺点:

  • 需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
  • 在实现深克隆时需要编写较为复杂的代码。

二、实现

1、UML类图

2、Prototype

package com.mfc.design.原型模式;

/**
 * @author MouFangCai
 * @date 2019/10/12 14:41
 */
public abstract class Prototype implements Cloneable  {

    private String id;
    protected String type;

    abstract void draw();

    public String getType(){
        return type;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

3、ConcretePrototypeA

package com.mfc.design.原型模式;

/**
 * @author MouFangCai
 * @date 2019/10/12 14:45
 */
public class ConcretePrototypeA extends Prototype {
    @Override
    void draw() {
        System.out.println("这是ConcretePrototypeA的draw()");
    }
    public ConcretePrototypeA(){
        type = "ConcretePrototypeA";
    }
}

4、ConcretePrototypeB

package com.mfc.design.原型模式;

/**
 * @author MouFangCai
 * @date 2019/10/12 14:45
 */
public class ConcretePrototypeB extends Prototype {
    @Override
    void draw() {
        System.out.println("这是ConcretePrototypeB的draw()");
    }
    public ConcretePrototypeB(){
        type = "ConcretePrototypeB";
    }

}

5、PrototypeCache

package com.mfc.design.原型模式;

import java.util.Hashtable;

/**
 * @author MouFangCai
 * @date 2019/10/12 14:45
 */
public class PrototypeCache {

    // 维护一个注册表
    private static Hashtable<String, Prototype> prototypeMap = new Hashtable<>();

    // 提供一个获取新实例的方法
    public static Prototype getprototype(String prototypeId) {
        Prototype cached = prototypeMap.get(prototypeId);
        return (Prototype) cached.clone();
    }

    // 对每种形状都运行数据库查询,并创建该形状
    // prototypeMap.put(prototypeId, Prototype);
    // 例如,我们要添加2种Prototype
    public static void loadCache() {
        ConcretePrototypeA A = new ConcretePrototypeA();
        A.setId("1");
        prototypeMap.put(A.getId(),A);

        ConcretePrototypeB B = new ConcretePrototypeB();
        B.setId("2");
        prototypeMap.put(B.getId(),B);
    }
}

6、Client_Prototype

package com.mfc.design.原型模式;

/**
 * @author MouFangCai
 * @date 2019/10/12 15:00
 */
public class Client_Prototype {

    public static void main(String[] args) {
        PrototypeCache.loadCache();

        Prototype clonedPrototype1 = (Prototype) PrototypeCache.getprototype("1");
        System.out.println("Prototype : " + clonedPrototype1.getType());

        Prototype clonedPrototype2 = (Prototype) PrototypeCache.getprototype("2");
        System.out.println("Prototype : " + clonedPrototype2.getType());
    }
}

三、原型模式分析

上面这个例子,参考自菜鸟教程:https://www.runoob.com/design-pattern/prototype-pattern.html(小编不是很理解这个原型模式的例子,感觉似乎没什么实际意义,只是new对象的操作换了个地方而已)

从上面这个例子分析,总感觉原型模式似乎有些问题。所以小编再次参考阅读了《大话设计模式》,详情请见下面的例子

1、问题描述

比如说,有一个使用场景需要不同的Person对象但是其name属性一样,但是age和score属性需要根据环境不同而设置不同的值

 2、Person_Prototype

package com.mfc.design.原型模式2;

/**
 * @author MouFangCai
 * @date 2019/10/12 16:12
 */
// 原型Prototype
public class Person_Prototype implements Cloneable {

    private String name;
    private int age;
    private int score;

    // 设置需要复制的属性(公有属性)
    public Person_Prototype(String name){
        this.name = name;
    }

    // 设置需要自定义的属性
    public void setMessage(int age, int score){
        this.age =age;
        this.score =score;
    }

    public void dispaly(){
        System.out.println("name:" + name + "----age:"+ age + "----score:" + score);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

3、Cilent客户端

package com.mfc.design.原型模式2;

/**
 * @author MouFangCai
 * @date 2019/10/12 15:00
 */
public class Client_Prototype {

    public static void main(String[] args) throws CloneNotSupportedException {

        Person_Prototype p1 = new Person_Prototype("mfc");
        p1.setMessage(18, 22);

        // 复制一个新的Person,并修改对应的细节属性
        Person_Prototype p2 = (Person_Prototype)p1.clone();
        p2.setMessage(24,44 );

        System.out.println("是否是同一个对象:" + (p1 == p2));
        p1.dispaly();
        p2.dispaly();
    }
}

结果如下:

是否是同一个对象:false
name:mfc----age:18----score:22
name:mfc----age:24----score:44

Process finished with exit code 0

4、分析

从运行结果,我们可以看到,Person对象被复制了一个,同时name属性保持一致,age被重新自定义,达到我们预期要求

备注:这只是 浅复制,如果Person对象有一个私有属性是对象时,就需要使用 深复制 进行实现,有兴趣者可自行百度。

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值