首页 > 其他分享 >设计模式-创建型-原型模式

设计模式-创建型-原型模式

时间:2023-09-01 13:56:44浏览次数:128  
标签:克隆 创建 QiTianDaSheng concretePrototype new 原型 设计模式 public

title: 设计模式-创建型-原型模式
keywords: 设计模式
cover: [https://s1.ax1x.com/2023/08/31/pP01Vit.png]
# sticky: 10
banner:  
  type: img
  bgurl: https://s1.ax1x.com/2023/08/31/pP01Vit.png
  bannerText: 设计模式-创建型-原型模式
categories: 设计模式
tags:
  - 设计模式
toc: false # 无需显示目录

原型模式

原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象

原型模式适用场景:

  • 类初始化消耗资源较多

  • 使用new生成一个对象需要非常繁琐的过程(数据准备、访问权限)

  • 构造函数比较复杂

  • 在循环体中产生大量对象

1、浅克隆

一个标准的原型模式应该这样设计,首先创建一个原型Prototype接口

/**
 * 原型Prototype接口
 * @author ss_419
 */
public interface Prototype {
    Prototype clone();
}

创建具体需要克隆的类ConcretePrototypeA:

/**
 * TODO 具体需要克隆的类
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/9/1 11:02
 */
public class ConcretePrototypeA implements Prototype{
    private int age;
    private String name;
    private List hobbies;



    /**
     * 实现Prototype原型类的clone方法
     * 注意:这里的克隆是浅克隆,对引用对象克隆的是地址,而不是全新的值
     * @return
     */
    @Override
    public ConcretePrototypeA clone() {
        // 原型模式:指定原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
        ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
        // 设置该对象原型类的属性
        concretePrototype.setAge(this.getAge());
        concretePrototype.setName(this.getName());
        concretePrototype.setHobbies(this.getHobbies());
        // 返回复制实例
        return concretePrototype;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public List getHobbies() {
        return hobbies;
    }

    public void setHobbies(List hobbies) {
        this.hobbies = hobbies;
    }
}

创建Client类:

/**
 * TODO 在客户端类中进行克隆操作-生成对象
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/9/1 11:18
 */
public class Client {
    // 注入原型对象
    private Prototype prototype;

    public Client(Prototype prototype) {
        this.prototype = prototype;
    }

    /**
     * 开始克隆,该方法只需指定克隆对象的类型即可
     * @return
     */
    public Prototype startClone(Prototype concretePrototype){
        return (Prototype)concretePrototype.clone();

    }
}

测试代码:

public class PrototypeTest {
    public static void main(String[] args) {
        // 创建一个具体的需要克隆的对象
        ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
        // 填充属性,方便测试
        concretePrototype.setAge(19);
        concretePrototype.setName("ukyo");
        List hobbies = new ArrayList<String>();
        hobbies.add("xxxx1");
        hobbies.add("xxxx2");
        hobbies.add("xxxx3");
        concretePrototype.setHobbies(hobbies);
        System.out.println("concretePrototype = " + concretePrototype);

        // 创建client对象,准备开始克隆s
        Client client = new Client(concretePrototype);
        ConcretePrototypeA clone =
                   // 这里的克隆仅仅对当前对象的值进行的复制
                (ConcretePrototypeA) client.startClone(concretePrototype);
        System.out.println("clone = " + clone);

        /***
         * 因为是浅拷贝,所以对象中的引用地址没有重新分配内存空间,就算进行了克隆,它们还是指向同一块内存空间
         * 可以看出,hobbies的引用地址是相同的,意味着复制的不是值,而是引用的地址
         *
         * 浅克隆只是完整复制了值类型数据,没有赋值引用对象
         */
        System.out.println("克隆对象中的引用类型地址:" + clone.getHobbies());
        System.out.println("原对象中的引用类型地址:" + concretePrototype.getHobbies());
        System.out.println("对象地址比较 => "+(concretePrototype.getHobbies() == clone.getHobbies()));
    }
}

2、深拷贝

/**
 * TODO 原型猴子类Monkey
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/9/1 11:28
 */
public class Monkey {
    public int height;
    public int weight;
    public Date birthday;
}
public class JinGuBang implements Serializable {
    public float h = 100;
    public float d = 10;

    public void big(){
        this.d *= 2;
        this.h *= 2;
    }

    public void small(){
        this.d /= 2;
        this.h /= 2;
    }
    
}
public class QiTianDaSheng extends Monkey implements Cloneable, Serializable {

    public JinGuBang jinGuBang;

    public QiTianDaSheng() {
        // 只是初始化
        this.birthday = new Date();
        this.jinGuBang = new JinGuBang();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {

        return this.deepClone();
    }

    /**
     * 创建深拷贝方法
     */
    public Object deepClone() {
        try {
            // 创建字节输出流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            // 读取输入流中的对象,并强转
            QiTianDaSheng copy = (QiTianDaSheng) ois.readObject();// 生成一个全新的copy对象
            copy.birthday = new Date();
            return copy;
        } catch (Exception e) {
            e.printStackTrace();
            // 克隆失败返回null
            return null;
        }
    }

    /**
     * 浅拷贝
     *
     */
    public QiTianDaSheng shallowClone(QiTianDaSheng target){
        QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
        // 从目标对象中拷贝值
        qiTianDaSheng.height = target.height;
        qiTianDaSheng.weight = target.weight;
        // 拷贝引用对象,这里很明显可以看出指向同一块内存空间
        qiTianDaSheng.jinGuBang = target.jinGuBang;

        qiTianDaSheng.birthday = new Date();
        return qiTianDaSheng;
    }

}

深拷贝测试:

/**
 * TODO 深拷贝测试
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/9/1 11:39
 */
public class DeepTest {
    public static void main(String[] args) {
        QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
        // 深拷贝
        try{
            QiTianDaSheng clone =
                    (QiTianDaSheng) qiTianDaSheng.clone();
            System.out.println("通过序列化操作进行深拷贝 => "+ (clone.jinGuBang == qiTianDaSheng.jinGuBang));
        }catch (Exception e){
            e.printStackTrace();
        }

        // 浅拷贝
        QiTianDaSheng q = new QiTianDaSheng();
        QiTianDaSheng n = q.shallowClone(q);
        System.out.println("浅克隆 => "+ (q.jinGuBang == n.jinGuBang));
    }
}

标签:克隆,创建,QiTianDaSheng,concretePrototype,new,原型,设计模式,public
From: https://www.cnblogs.com/atwood-pan/p/17671666.html

相关文章

  • 设计模式-创建型-单例模式
    title:设计模式-创建型-单例模式keywords:设计模式cover:[https://s1.ax1x.com/2023/08/31/pP01Vit.png]#sticky:10banner:type:imgbgurl:https://s1.ax1x.com/2023/08/31/pP01Vit.pngbannerText:设计模式-创建型-单例模式categories:设计模式tags:-......
  • 达梦DM8手动创建AWR报告
    达梦数据库AWR报告创建方式如下:1、启用系统包和AWR包:SQL>CALLSP_INIT_AWR_SYS(1);DMSQL过程已成功完成已用时间:00:00:01.380.执行号:59500.SQL>CALLSP_CREATE_SYSTEM_PACKAGES(1);DMSQL过程已成功完成已用时间:00:00:03.403.执行号:59501.2、查询AWR......
  • mysql 创建只读权限账号
    命令行登录mysql-uroot-p创建只读权限的账号【将<username>替换为用户名, <password>替换为密码。'%' 表示该账号可以从任何主机连接。如果希望限制连接的主机,可以将 '%' 替换为具体的主机名或IP地址。】CREATEUSER'<username>'@'%'IDENTIFIEDBY'<password>......
  • windows10创建conda环境失败:CondaHTTPError: HTTP 000 CONNECTION FAILED for url <htt
    问题描述创建新环境时,报错,创建不成功Collectingpackagemetadata(current_repodata.json):doneSolvingenvironment:doneCondaHTTPError:HTTP000CONNECTIONFAILEDforurl<https://conda.anaconda.org/conda-forge/linux-64/current_repodata.json>Elapsed:-AnHTTP......
  • 23种设计模式之代理模式
    代理设计模式(ProxyDesignPattern)是一种结构型设计模式,它为其他对象提供一个代理,以控制对这个对象的访问。代理模式可以用于实现懒加载、安全访问控制、日志记录等功能。在设计模式中,代理模式可以分为静态代理和动态代理。静态代理是指代理类在编译时就已经确定,而动态代理是指代理......
  • 23种设计模式之建造者模式
    Builder模式,也叫生成器模式。创建者模式主要包含以下四个角色:产品(Product):表示将要被构建的复杂对象。抽象创建者(AbstractBuilder):定义构建产品的接口,通常包含创建和获取产品的方法。具体创建者(ConcreteBuilder):实现抽象创建者定义的接口,为产品的各个部分提供具体实现。指挥者(Direc......
  • 通过动态创建a标签,循环批量下载文件所遇到的问题记录
    1.现象:直接for循环动态创建a标签后,进行click事件触发下载时,你会发现浏览器只下载了最后一个文件原因:浏览器下载时,太快的话,会取消上次的下载解决方法一:可添加settimeout定时器,进行一定时间延迟,比如300毫秒,把下载触发的事件放到定时器中即可。2.解决方法二通过ifram......
  • 23种设计模式之工厂模式
    工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。简单工厂(SimpleFactory):简单工厂叫作静态工厂方法模式(StaticFactoryMethodPattern)。假设一个场景,需要一个资源加载器,要根据不同的url进行资源加载,但是如果将所有的加载实现代码全部封装在了一个load方法中,就会导致......
  • 23种设计模式之单例模式
    单例设计模式(SingletonDesignPattern):一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式。如何实现一个单例:常见的单例设计模式,有如下五种写法,在编写单例代码的时候要注意以下几点:1、构造器需要私有化2、暴露一个公共的获取单例对象的接口3......
  • 使用samba创建共享文件夹(Linux - Windows)
    1.安装samba有些Linux已经自带了samba$sudoaptinstallsamba-y2.配置防火墙详情请参考https://zhuanlan.zhihu.com/p/508580900,因本人使用的是MX23,不是很会设置,且无其它安全需求,故直接关闭防火墙3.配置samba$sudovim/etc/samba/smb.conf#按个人需要可以备份......