热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

原型模式的关键

本文主要介绍关于Prototype,Pattern,设计模式,原型模式,原型管理器的知识点,对【设计模式|原型模式】和【原型模式的关键】有兴趣的朋友可以看下由【ChaITSimpleLove】投稿

本文主要介绍关于Prototype,Pattern,设计模式,原型模式,原型管理器的知识点,对【设计模式 | 原型模式】和【原型模式的关键】有兴趣的朋友可以看下由【ChaITSimpleLove】投稿的技术文章,希望该技术和经验能帮到你解决你所遇的【设计模式(Design pattern)】相关技术问题。

原型模式的关键

1 | 原型模式概述

原型模式是一种特殊的创建型模式,它通过复制一个已有对象来获取更多相同或相似的对象。原型模式可以提高系统同类型对象的创建效率,简化创建过程。?

《西游记》中”孙悟空拔毛变猴“的故事几乎人人皆知,孙悟空用猴毛根据自己的形象,复制出很多和自己长的一摸一样的”分身“。类似这种场景在面向对象的软件设计领域被称为原型模式,孙悟空则被成为原型对象。

1.1 原型模式的定义 原型模式:使用原型实例指定待创建对象的类型,并通过复制这个原型来创建新的对象。 Prototype Pattern:Specify the kinds of objects to create using a protptypical instance, and create new objects by copying this protptype. 1.2 原型模式的工作原理 将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现新对象的创建过程。这种创建新对象的过程也称为”克隆对象“,创建新对象的工厂就是原型类自身,工厂方法由负责复制原型对象的克隆方法来实现。

注意:通过克隆对象创建的对象是全新的对象,他们在内存中拥有新的地址。通常对克隆所产生的新对象进行修改对原型对象不会造成任何影响,每一个克隆对象都是相互独立的。通过对克隆对象进行修改后,可以得到一系列相似但不完全的对象。

2 | 原型模式的结构与实现 2.1?原型模式的结构

原型模式包含以下 3 个角色:

(1) Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,它可以是抽象类也可以是接口,甚至可以是具体实现类。(2) ConcretePrototvpe(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。(3) Client(客户类):在客户类中,让一个原型对象克隆自身从而创建一个新的对象,只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对负由干家白米社对抽鱼百用版Prntotvne编程,因此,用户可以根据需要选择具体原米,系经且有校缸的可扩民抖画加成百推几休原型类都很方便。 2.2 原型模式的 浅克隆深克隆

根据在复制原型对象的同时是否复制包含在原型对象中引用类型的成员变量,原型模式的克隆机制分为两种:浅克隆(Shallow Clone)深克隆(Deep Clone),有时也称作浅拷贝和深拷贝。

(1)浅克隆(Shallow Clone)

在浅克隆中,如果原型对象的成员亦量是值类刑(如 int、double、byte、bool 、char 等基本数据类型)将复制一份给克降对象,如果原型对象的成员变量是引用类型(如类、接口、数组等复杂数据类型),则将引用对象的地址复制一份给克降对象,也就是说,原型对象和克隆对象的成员变量指向相同的内存地址。简单来说,在浅克隆中,当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。

(2)深克隆(Deep Clone)

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将被复制。

2.2?原型模式的实现

实现原型模式的关键在于如何实现克隆方法,在 C# 中有两种常用的克隆实现方法:

2.2.1 通用克隆实现方法

典型示例代码如下:

abstract class Prototype 
{
    public abstract Prototype Clone();
}

class ConcretePrototype : Prototype
{
    ///  /// 成员变量 /// 
    public string Attr { get; set; }

    ///  /// 克隆方法,通过赋值的方式来实现对象的复制。 /// 
    /// 
  
    public override Prototype Clone() => new ConcretePrototype
    {
        Attr = Attr //成员变量赋值
    };
}

?客户端调用示例代码:

// 1.创建 ConcretePrototype 对象作为原型。
ConcretePrototype prototype = new ConcretePrototype();
// 2. 原型实例对象 prototype 调用克隆方法 Clone() 创建克隆对象。
ConcretePrototype copy = (ConcretePrototype)prototype.Clone();

?注:此方法是原型模式的通用方法,与编程语言本身的特性无关,除 C# 外,其他面向对象编程语言也可以使用这种形式来实习原型对象的克隆。上面的克隆方法??Clone() 中,如果通过创建一个全新的成员对象来实现复制,则是一种深克隆实现方案。C# 语言中的字符串 (string/String)对象存在特殊性,只要两个字符串的内同相同,无论是值赋值还是创建新对象,它们在内存中始终只有一份。了解更多可查看 ”C# 字符串驻留机制“。

参考:【字符串的不可变性和驻留机制】https://www.cnblogs.com/SignX/p/10933482.html

2.2.2 C# 中的?MemberwiseClone() 方法和?ICloneable 接口

在 C# 语言中,提供了一个? MemberwiseClone() 方法用于实现浅克隆,该方法使用很方便,之间调用一个已有对象的 MemberwiseClone() 方法即可实现对象克隆。示例代码如下:

class Member { }

class ConcretePrototypeA 
{
    ///  /// 成员变量 /// 
    public Member MyMember { get; set; }

    ///  /// 克隆方法,通过赋值的方式来实现对象的复制。 /// 
    /// 
  
    public ConcretePrototypeA Clone() => (ConcretePrototypeA)this.MemberwiseClone(); //浅克隆      
}

?客户端调用,测试输出结果证实该克隆方法是浅克隆。

?ICloneable 接口充当了抽象原型类的角色,具体原型类通常作为实现该接口的子类实现深克隆。示例代码如下:

class ConcretePrototypeB: System.ICloneable
{
    ///  /// 成员变量 /// 
    public Member MyMember { get; set; }

    ///  /// 实现深克隆 /// 
    /// 
  
    public object Clone()
    {
        ConcretePrototypeB copy = this.MemberwiseClone() as ConcretePrototypeB; //对象转换
        Member newMember = new Member();
        copy.MyMember = newMember;
        return copy;
    }
}

客户端调用,测试输出结果证实该克隆方法是深克隆。

3 | 原型管理器(Prototype Manager)

原型管理器(Prototype Manager)将多个原型对象存储在一个集合中供客户端使用,他是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某一个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得。在原型管理器中针对抽象类进行编程,方便扩展,该结构如下:

?原型管理器 PrototypeManager 代码实现:

using System.Collections;

namespace PrototypePattern
{
    ///  /// 原型管理器-PrototypeManager /// 
    class PrototypeManager
    {
        #region SingleProfit 单例模式
        //创建私有化静态obj锁
        private static readonly object _ObjLock = new object();
        //创建私有静态字段,接收类的实例化对象
        private static volatile PrototypeManager _SingleProfit = null; //volatile 促进线程安全,保证线程有序执行 
        //构造函数私有化
        private PrototypeManager() { }
        //创建单利对象资源并返回
        public static PrototypeManager CreateSingleProfitObj()
        {
            if (_SingleProfit == null)
            {
                lock (_ObjLock)
                {
                    if (_SingleProfit == null)
                    {
                        _SingleProfit = new PrototypeManager();
                    }
                }
            }
            return _SingleProfit;
        } 
        #endregion

        ///  /// Hashtable 存储原型对象 /// 
        private readonly static Hashtable hashTable = new Hashtable();

        ///  /// Hashtable 新增原型对象 /// 
        /// 
        /// 
        public void Add(string key, Prototype prototype) 
        {
            hashTable.Add(key,prototype);
        }

        ///  /// 获取克隆对象 /// 
        /// 
        /// 
  
        public Prototype Get(string key) 
        {
            Prototype copy = ((Prototype)hashTable[key]).Clone(); //通过(内置)克隆方法创建新对象
            return copy;
        }
    }
}

在实际的开发中,PrototypeManager 类通常设计为单例类(单例模式),确保系统中有且仅有一个?PrototypeManager 对象,既有利于节省系统资源,还可以更好地对原型管理器对象进行控制。添加两个类分别是?ConcretePrototypeC?和?ConcretePrototypeD

#region 配合 PrototypeManager 使用
class ConcretePrototypeC : Prototype
{
    public override Prototype Clone()
    {
        return (ConcretePrototypeC) this.MemberwiseClone();
    }
}

class ConcretePrototypeD : Prototype
{
    public override Prototype Clone()
    {
        return (ConcretePrototypeD) this.MemberwiseClone();
    }
}
#endregion

客户端调用方法

完整代码示例请查看=》?https://gitee.com/dolayout/DesignPatternOfCSharp/tree/master/DesignPatternOfCSharp/PrototypePattern

4 | 原型模式的优缺点与适用环境

原型模式作为一种快速创建大量相同或相似对象的方式,在软件开发中的应用较为泛,很多软件提供的复制(Ctrl+C)粘贴(Ctrl+V)操作就是原型模式的典型应用。

4.1 原型模式的主要优点 (1)当要创建的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过制一个已有实例可以提高新实例的创建效率。(2)扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统没有任何影响。(3)原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在型类中的克隆方法实现的,无须专门的工厂类来创建产品。(4)可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其态保存起来,以便在需要的时候使用(例如恢复到某一历史状态),可辅助实现撤销操作。 4.2 原型模式的主要缺点 (1)需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已的类进行改造时,需要修改源代码,违背了 开闭原则。(2)在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。 4.3 原型模式的适用环境 (1)创建新对象成本较大(例如初始化需要占用较长的时间,占用太多的CPU资源或网络资源),新对象可以通过复制已有对象来获得,如果是相似对象,则可以对其成员变量稍作修改。(2)系统要保存对象的状态,而对象的状态变化很小。(3)需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

本文《设计模式 | 原型模式》版权归ChaITSimpleLove所有,引用设计模式 | 原型模式需遵循CC 4.0 BY-SA版权协议。


推荐阅读
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 提升视觉效果:Unity3D中的HDR与Bloom技术(高动态范围成像与光线散射)
    提升视觉效果:Unity3D中的HDR与Bloom技术(高动态范围成像与光线散射) ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 题目要求解决一个有趣的编程挑战,即计算由四个自然数 \( p, q, r, s \) 组成的分数序列的和。具体来说,需要编写一个 C# 程序来处理这些自然数,并通过特定的数学运算得出最终结果。该任务不仅考验编程技能,还涉及对数学公式的理解和应用。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 利用ZFS和Gluster实现分布式存储系统的高效迁移与应用
    本文探讨了在Ubuntu 18.04系统中利用ZFS和Gluster文件系统实现分布式存储系统的高效迁移与应用。通过详细的技术分析和实践案例,展示了这两种文件系统在数据迁移、高可用性和性能优化方面的优势,为分布式存储系统的部署和管理提供了宝贵的参考。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • CTF竞赛中文件上传技巧与安全绕过方法深入解析
    CTF竞赛中文件上传技巧与安全绕过方法深入解析 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
author-avatar
U友39373533
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有