原型模式Prototype

本文深入解析了原型模式的概念、应用场景及其实现方式,并通过具体案例展示了如何利用原型模式提高代码效率和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

指从一个样板对象中复制出一个内部属性一致的对象,其实就是克隆。而被复制的对象就叫做原型,多用于创建复杂的或者构造耗时的实例

定义

用原型实例指定创建对象的种类, 并通过拷贝这些原型创建新的对象.

场景

  • 类初始化需要消耗非常多的资源, 这个资源包括数据,硬件资源等, 可通过原型拷贝避免这些消耗
  • 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限, 同样可以使用原型模式
  • 一个对象需要提供给其他对象访问, 并且会能会对其修改属性, 可以用原型拷贝多个对象提供使用

使用 Cloneable接口 , Objecct.clone()方法

  • 先看下Object.clone()方法说明
    表示:创建一个对象的副本。注意,clone不同于赋值,赋值是对象的引用传递,而clone是则创建一个与原型有相同数据的对象。
  protected native Object clone() throws CloneNotSupportedException;

看下clone后的区别

x.clone() != x;  //可以看到clone后的对象与原型不是同一个引用

x.clone().getClass() == x.getClass();  //但还是同个对象类型

x.clone().equals(x) == true;    //数据一样

如果一个对象使用object.clone的时候没有实现Cloneable接口,则会抛出一个ClassNotSupportedException异常。
此外,所有的array数组默认都已经实现了Cloneable接口

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 例子
public class WordDocument implements Cloneable{
    // 文本
    public String mText;
    // 图片名列表
    public ArrayList<String> mImages = new ArrayList<String>();
    @Override
    protected WordDocument clone() {
        try {
            // 通过本地方法特殊途径, 构建一个对象
            WordDocument doc = (WordDocument) super.clone();
            //mText 虽然是对象, 但是因为是 String 类型, 属于安全类型, 由于final类,实例不可更改的特性. 如果对副本进行字符串的修改, 只不过是把原引用删除,重新指向了新的字符串.
            doc.mText = this.mText;
            // 因为Image是引用类型, 这样直接赋值属于浅拷贝, 再次对集合进行clone. 实现wordDocument的深拷贝
            doc.mImages = (ArrayList<String>) this.mImages.clone();
            // 这里进行修改 那么此时属于浅拷贝 
            //doc.mImages = this.mImages;
            return doc;
        }catch (Exception ex){}
        return null;
    }

}

本质也就是类实现Cloneable接口,再通过super.clone()构造有一个本类对象的一个初始状态,然后给被拷贝的对象赋值而已。
这里区别一下浅拷贝和深拷贝
* 浅拷贝(影子拷贝):拷贝出来的对象并不是完全的一份独立对象。新的对象属性中引用了原始对象中的数据。如代码中 doc.mImages = this.mImages 可以看到这里只是引用赋值了而已
* 深拷贝:拷贝出来的对象的属性与原始对象没有关联,是完全独立开来的一个副本。如代码中  doc.mImages = (ArrayList) this.mImages.clone(); 

拷贝

拷贝对象一般有两种方法,第一种就是new一个新的对象,第二种就是clone。
当new构造对象比较耗时和成本较高时,通过clone就可以获得效率提升

Android源码

@Override
public Object clone() {
   return new Intent(this);
}

/**
* Copy constructor.
*/
public Intent(Intent o) {
   this.mAction = o.mAction;
   this.mData = o.mData;
   this.mType = o.mType;
   this.mPackage = o.mPackage;
   this.mComponent = o.mComponent;
   this.mFlags = o.mFlags;
   this.mContentUserHint = o.mContentUserHint;
   if (o.mCategories != null) {
       this.mCategories = new ArraySet<String>(o.mCategories);
   }
   if (o.mExtras != null) {
       this.mExtras = new Bundle(o.mExtras);
   }
   if (o.mSourceBounds != null) {
       this.mSourceBounds = new Rect(o.mSourceBounds);
   }
   if (o.mSelector != null) {
       this.mSelector = new Intent(o.mSelector);
   }
   if (o.mClipData != null) {
       this.mClipData = new ClipData(o.mClipData);
   }
}

可以看到Intent这里处理是通过new进行数据复制,成本比较低

实战

当登录模块登录成功之后, 会把一些个人信息,token等信息在保存类中的某个数据结构上, 并通过一个方法对外暴露出去, 提供其他模块使用. 但是如果你返回的是一个数据结构也就是一个对象, 这个对象包含了很多个人信息, 但是正常来说, 对于外部应该只提供查看数据的能力, 不应该提供修改的能力.

也就是克隆一个对象给你读取数据,尽管它修改了数据,但毕竟不是修改在原始的数据上

所以这个使用, 就可以对登录模块对外暴露的方法进行修改, 利用 原型模式 对外返回的是一个内部数据的 深拷贝 , 这样就把可能出现的隐患彻底的隔绝了.

注意

原型模式 是通过内存中二进制流的方式拷贝, 要比直接通过 new 一个对象性能更好, 特别是循环体内产生大量对象是. 但是注意, 因为是 二进制流的拷贝 , 所以构造函数是不会执行的. 这点要明确记牢.

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值