广告
返回顶部
首页 > 资讯 > 后端开发 > Python >java设计模式--原型模式详解
  • 541
分享到

java设计模式--原型模式详解

2024-04-02 19:04:59 541人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录引例原型模式浅拷贝在原先Sheep类基础上实现Cloneable接口,重写clone方法。客户端调用Sheep类新添的Cow类客户端调用克隆深拷贝1.Cow类也实现Cloneab

引例

问题:

现在有一只羊(包含属性:名字Dolly、年龄2),需要克隆10只属性完全相同的羊。

一般解法:

定义Sheep类表示羊,包括构造器、getter()和toString()。


public class Sheep {
    private String name;
    private int age;
    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在客户端实例化多利,然后再根据多利的属性去实例化10只羊。


public class Client {
    public static void main(String[] args) {
        Sheep sheepDolly=new Sheep("Dolly",2);
        Sheep sheep1 = new Sheep(sheepDolly.getName(), sheepDolly.getAge());
        Sheep sheep2 = new Sheep(sheepDolly.getName(), sheepDolly.getAge());
        Sheep sheep3 = new Sheep(sheepDolly.getName(), sheepDolly.getAge());
        //....
        System.out.println(sheep1+",hashCode:"+sheep1.hashCode());
        System.out.println(sheep2+",hashCode:"+sheep2.hashCode());
        System.out.println(sheep3+",hashCode:"+sheep3.hashCode());
        //...
    }
}

运行结果

在这里插入图片描述

优缺点:

这种方法是我们首先很容易就能想到的,也是绝大多数人的第一做法。

但缺点也很明显,每次创建新对象时需要获取原始对象的属性,对象复杂时效率很低;此外不能动态获得对象运行时的状态,若类增减属性需要改动代码。

下面我们看下原型模式的解法。

原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。即用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。

工作原理:将原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。即用基类Object的clone()方法或序列化。

UML类图:

在这里插入图片描述

  • Prototype:原型类,声明一个克隆自己的接口
  • ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作
  • Client: 客户端让一个原型对象克隆自己,从而创建一个新的对象

原型模式又可分为浅拷贝和深拷贝,区别在于对引用数据类型的成员变量的拷贝,小朋友你是否有很多问号? 不急 ,看完这两种方法实现你就懂了。

浅拷贝

在原先Sheep类基础上实现Cloneable接口,重写clone方法。


public class Sheep implements Cloneable{
    private String name;
    private int age;
    @Override
    protected Object clone()  {//克隆该实例,使用默认的clone方法来完成
        Sheep sheep = null;
        try {
            sheep = (Sheep)super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

客户端调用


public class Client {
    public static void main(String[] args) {
        Sheep sheepDolly=new Sheep("Dolly",2);
        Sheep sheep1 = (Sheep)sheepDolly.clone();
        Sheep sheep2 = (Sheep)sheepDolly.clone();
        Sheep sheep3 = (Sheep)sheepDolly.clone();
        //....
        System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
        System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode());
        System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode());
        //...
    }
}

运行结果

在这里插入图片描述

至此,原型模式的浅拷贝也成功克隆了三个对象,但是看进度条发现并不简单。

现在小羊有了一个朋友小牛,Sheep类添加了一个引用属性Cow,我们同样再克隆一遍。

Sheep类


public class Sheep implements Cloneable{
    private String name;
    private int age;
    public Cow friend;//新朋友Cow对象,其余不变
    @Override
    protected Object clone()  {
        Sheep sheep = null;
        try {
            sheep = (Sheep)super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

新添的Cow类


public class Cow {
    private String name;
    private int age;
    public Cow(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Cow{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

客户端调用克隆


public class Client {
    public static void main(String[] args) {
        Sheep sheepDolly=new Sheep("Dolly",2);
        sheepDolly.friend=new Cow("Tom",1); //并实例化朋友
        Sheep sheep1 = (Sheep)sheepDolly.clone();
        Sheep sheep2 = (Sheep)sheepDolly.clone();
        Sheep sheep3 = (Sheep)sheepDolly.clone();
        //....
        System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
        System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'\n');
        System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode());
        System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'\n');
        System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode());
        System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'\n');
        //...
    }
}

运行结果

在这里插入图片描述

通过运行结果发现,浅拷贝通过Object的clone()成功克隆实例化了三个新对象,但是并没有克隆实例化对象中的引用属性,也就是没有克隆friend对象(禁止套娃 ),三个新克隆对象的friend还是指向原克隆前的friend,即同一个对象。

这样的话,他们四个的friend是引用同一个,若一个对象修改了friend属性,势必会影响其他三个对象的该成员变量值。

小结:

  • 浅拷贝是使用默认的 clone()方法来实现
  • 基本数据类型的成员变量,浅拷贝会直接进行值传递(复制属性值给新对象)。
  • 引用数据类型的成员变量,浅拷贝会进行引用传递(复制引用值(内存地址)给新对象)。

深拷贝

方法一:

机灵的人儿看出,再clone一遍cow不就好了,但是手动递归下去不推荐。

1.Cow类也实现Cloneable接口


public class Cow implements Cloneable{
    private String name;
    private int age;
    public Cow(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //无引用类型,直接clone即可
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); //直接抛出了,没用try-catch
    }
    @Override
    public String toString() {
        return "Cow{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Sheep类的clone再添加调用cow的clone


public class Sheep implements Cloneable{
    private String name;
    private int age;
    public Cow friend;//新朋友Cow对象,其余不变
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //完成对基本数据类型(属性)和String的克隆
        deep = super.clone();
        //对引用类型的属性,进行再次clone
        Sheep sheep = (Sheep)deep;
        sheep.friend  = (Cow)friend.clone();
        return sheep;
    }
    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

客户端调用


public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheepDolly=new Sheep("Dolly",2);
        sheepDolly.friend=new Cow("Tom",1); //并实例化朋友
        Sheep sheep1 = (Sheep)sheepDolly.clone();
        Sheep sheep2 = (Sheep)sheepDolly.clone();
        Sheep sheep3 = (Sheep)sheepDolly.clone();
        //....
        System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
        System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'\n');
        System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode());
        System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'\n');
        System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode());
        System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'\n');
        //...
    }
}

运行结果

在这里插入图片描述

方法二:

通过对象序列化实现深拷贝(推荐)

1.Cow类实现序列化接口,不必实现Cloneable接口了


public class Cow implements Serializable {
    private String name;
    private int age;
    public Cow(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Cow{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2.在Sheep类实现序列化接口


public class Sheep implements Serializable { //实现序列化接口
    private String name;
    private int age;
    public Cow friend;

    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public Object deepClone() { //深拷贝
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            Sheep sheep = (Sheep) ois.readObject();
            return sheep;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                System.out.println(e2.getMessage());
            }
        }
    }
}

3.客户端调用


public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheepDolly=new Sheep("Dolly",2);
        sheepDolly.friend=new Cow("Tom",1); //并实例化朋友
        Sheep sheep1 = (Sheep)sheepDolly.deepClone();
        Sheep sheep2 = (Sheep)sheepDolly.deepClone();
        Sheep sheep3 = (Sheep)sheepDolly.deepClone();
        //....
        System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
        System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'\n');
        System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode());
        System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'\n');
        System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode());
        System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'\n');
        //...
    }
}

运行结果

在这里插入图片描述

原型模式总结:

  • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
  • 可以不用重新初始化对象,动态地获得对象运行时的状态。
  • 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
  • 若成员变量无引用类型,浅拷贝clone即可;若引用类型的成员变量很少,可考虑递归实现clone,否则推荐序列化。

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: java设计模式--原型模式详解

本文链接: https://www.lsjlt.com/news/130791.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • java设计模式--原型模式详解
    目录引例原型模式浅拷贝在原先Sheep类基础上实现Cloneable接口,重写clone方法。客户端调用Sheep类新添的Cow类客户端调用克隆深拷贝1.Cow类也实现Cloneab...
    99+
    2022-11-12
  • Java设计模式之原型模式详解
    目录一、前言二、优点及适用场景三、原型模式的注意事项四、浅复制和深复制五、浅复制demo演示六、深复制demo演示一、前言 原型模式是一种比较简单的模式,也非常容易理解,实现一个接口...
    99+
    2022-11-12
  • Java设计模式之java原型模式详解
    目录介绍角色Java语言提供的clone()方法代码演示—克隆羊结论深浅拷贝深浅拷贝探讨实现深克隆的方式一 : 手动对引用对象进行克隆实现深克隆的方式一 :序列化原型模式对单例模式的...
    99+
    2022-11-12
  • Java设计模式之原型模式的示例详解
    目录定义案例需求方案一方案二对比分析总结 定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 即实现了一个原型接口,该接口用于创建当前对象的克隆,当直接创建对象的代...
    99+
    2022-11-13
  • java设计模式:原始模型模式
    目录什么是原始模型模式原始模型模式中的角色抽象原型角色(Prototype)具体原型角色(ConcretePrototype)A...
    99+
    2022-11-12
  • Java 超详细讲解设计模式之原型模式讲解
    目录传统方式原型模式基本介绍原型模式在spring框架中源码分析深入讨论-浅讨论和深拷贝原型模式的注意事项和细节传统方式 克隆羊问题 现在有一只羊 tom,姓名为: tom,年龄为:...
    99+
    2022-11-13
  • Java设计模式之原型设计示例详解
    目录简单说一下(定义)稍微夸一下(优缺点)顺便提一下(适用场景)着重讲一下(深、浅克隆)多多用一下(结构、代码实现)简单说一下(定义) 什么是原型模式:原型模式是用于创建重复的对象,...
    99+
    2022-11-13
  • JAVA设计模式---原型模式你了解吗
    目录介绍角色Java语言提供的clone()方法代码演示—克隆羊结论深浅拷贝深浅拷贝探讨实现深克隆的方式一 : 手动对引用对象进行克隆实现深克隆的方式二 :序列化原型模式对单例模式的...
    99+
    2022-11-12
  • Java设计模式中的原型模式讲解
    目录介绍原型模式深拷贝与浅拷贝原型模式代码总结介绍 原型模式 在Java中,原型模式是一种创建型设计模式,它允许通过复制一个现有对象来创建一个新对象,而不是通过创建新的对象来初始化一...
    99+
    2023-05-18
    Java 原型设计模式 Java 设计模式 Java 原型模式
  • Golang设计模式之原型模式详细讲解
    目录原型模式概念示例原型模式 原型是一种创建型设计模式, 使你能够复制对象, 甚至是复杂对象, 而又无需使代码依赖它们所属的类。 所有的原型类都必须有一个通用的接口, 使得即使在对象...
    99+
    2023-01-11
    Go原型模式 Go设计模式
  • Android常用设计模式之原型模式详解
    目录前言一、基本使用二、对象与集合的使用三、浅拷贝与深拷贝四、Kotlin的应用总结前言 什么是原型模式? 它是指创建对象的种类,并通过拷贝这些原型创建新的对象。 它是用于创建重复的...
    99+
    2022-11-13
    Android 设计模式原型模式 Android 原型模式
  • Javascript设计模式之原型模式详细
    目录1、原型模式示例一示例二示例三2、观察者模式1、原型模式 原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能、降低内存占用、代码复用的效果。 示例一 ...
    99+
    2022-11-12
  • JavaScript设计模式之原型模式详情
    目录前言案例回顾原型的拓展前言 设计模式呢最多的可能是用到类,我们去通过类来封装一些实用的方法,通过设计模式去实现各个方法之间的解耦等,由于JS中的继承是用原型链继承的,所以原型模式...
    99+
    2022-11-13
  • 怎么理解Java设计模式的原型模式
    本篇内容主要讲解“怎么理解Java设计模式的原型模式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解Java设计模式的原型模式”吧!一、前言单例模式可以避免重复创建消耗资源的对象,但是却不...
    99+
    2023-06-25
  • 深入理解Java设计模式之原型模式
    目录一、前言二、什么是原型模式三、原型模式的适用场景四、原型模式的实现1.浅拷贝实现2.深拷贝实现五、总结一、前言 单例模式可以避免重复创建消耗资源的对象,但是却不得不共用对象。若是...
    99+
    2022-11-12
  • Java设计模式的事件模型详解
    目录监听模式参与的角色事件、事件源、监听器之间的关系举个粒子总结监听模式 事件模型实现了监听模式,监听模式简单来说就是事件源经过事件的封装传给监听器,当事件源触发事件后,监听器接收到...
    99+
    2022-11-13
  • Java设计模式——工厂设计模式详解
    工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类。工厂模式的形态工厂模式主要用一下几种形态:简单工厂(Simple Factory)。2:工厂方法(Factory Method)。3:抽象工厂(Abstract...
    99+
    2023-05-30
    java 设计模式 ava
  • Java 深入理解创建型设计模式之原型模式
    1.思考问题 现在有一只羊 tom,姓名为: tom,年龄为:1,颜色为:白色,请编写程序创建和 tom羊属性完全相同的10只羊。 按照传统的思路来,我们可能会按照下面的方式去写。 ...
    99+
    2022-11-13
  • Java结构型设计模式之装饰模式详解
    目录介绍实现优缺点介绍 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更灵活。 主要解决:我们扩展一个类常使用继承方式实现,由于继承为类引入静态特征,...
    99+
    2023-05-14
    Java设计模式装饰模式 Java装饰模式
  • Java结构型设计模式之组合模式详解
    目录组合模式应用场景优缺点主要角色组合模式结构分类透明组合模式创建抽象根节点创建树枝节点创建叶子节点客户端调用安全组合模式创建抽象根节点创建树枝节点创建叶子节点客户端调用组合模式 组...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作