原型模式 订阅
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 展开全文
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
信息
外文名
Prototype
问    题
结构复杂的对象”的创建工作
实    现
clone()方法来实现对象的克隆
中文名
原型模式
模    式
Prototype
原型模式定义
原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。 [1] 
收起全文
精华内容
下载资源
问答
  • 本文实例讲述了Python设计模式原型模式。分享给大家供大家参考,具体如下: 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 一个原型模式的简单demo: #!/usr/bin/...
  • 主要介绍了设计模式中的原型模式在iOS应用开发中的作用,示例代码为传统的Objective-C,需要的朋友可以参考下
  • 主要介绍了C++设计模式原型模式,本文讲解了什么是原型模式、为什么要使用原型模式、代码实例等内容,需要的朋友可以参考下
  • Java设计模式——原型模式 原型模式Java设计模式——原型模式概念使用场景Java里的克隆代码理解prototype(原型)问题总结优缺点模型优点模型缺点 概念 ​ 原型模式是创建型模式的最后一种,讲到原型模式就不得不提到...
  • 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。 正文 对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是创建的一个对象作为另外一个...
  • 原型模式的意图是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 适用性  当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者 为了避免创建一个与产品类层次平行的工厂类层次时;...
  • 原型模式原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 原型模式本质就是克隆对象,所以在对象初始化操作比较复杂的情况下,很实用,能大大降低耗时,提高性能,因为“不用重新初始化对象,...
  • 主要介绍了php设计模式中的原型模式,使用php实现原型模式,感兴趣的小伙伴们可以参考一下
  • 主要介绍了JavaScript设计模式原型模式,简单描述了原型模式的概念、原理,并结合实例形式分析了ES5与ES6实现原型模式的相关操作技巧,需要的朋友可以参考下
  • 原型模式(Prototype Pattern),是一种创建型设计模式,指的是以原型实例指定待创建对象的种类,并通过拷贝(克隆)原型对象来创建新的对象。


    1 前言

      本文描述C++常用设计模式——原型模式,包括其含义、特点、优缺点、适用场景以及实现过程步骤,并以C++语言实现具体例子。

    相关文章:

    设计模式回顾——原型模式
    设计模式回顾——观察者模式
    设计模式回顾——模板模式
    设计模式回顾——策略模式
    设计模式回顾——适配器模式
    设计模式回顾——建造者模式
    设计模式回顾——工厂模式
    设计模式回顾——单例模式
    设计模式回顾——设计模式概念与基本原则


    2 什么是原型模式

      原型模式(Prototype Pattern),是一种创建型设计模式,指的是以原型实例指定待创建对象的种类,并通过拷贝(克隆)原型对象来创建新的对象。原型模式的核心和关键字是“对象拷贝”。


    2.1 原型模式组成

      原型模式由抽象原型(Abstract Prototype )具体原型(Concrete Prototype )客户(Client) 三个要素组成。


    • 抽象原型(Abstract Prototype ), 声明一个抽象原型父类,定义自身实例拷贝接口
    • 具体原型(Concrete Prototype ), 继承Abstract Prototype 类,实现抽象接口,返回拷贝对象
    • 客户(Client),客户调具体原型对象方法创建一个新的对象,严格来说客户不属于原型模式的一部分

    2.2 原型模式UML图

      根据原型模式的组成要素,以及它们之间的关系,画出原型模式的UML图如下。


    在这里插入图片描述

    原型模式UML图

    2.3 原型模式作用

      原型模式的功能与拷贝构造函数一样,都是用于创建新对象。但原型模式可以动态获取当前对象运行时的状态。


    3 原型模式优缺点

    优点:

    • 效率高、资源开销小

      使用原型模式创建对象比直接new一个对象效率要高,而且资源开销小,因为原型模式拷贝对象是一个本地方法过程,直接操作内存中的二进制流 。

    • 使用便捷

      简化对象创建过程,隐藏拷贝细节,用户无需知道创建细节。

    • 动态过程

      可以动态创建程序运行过程属性发生变化的对象,且创建的对象与运行对象互不干扰。


    不足:

    • 违背开闭原则

      原型模式需要为每一个类实现一个拷贝方法,由于拷贝方法在类内部实现,如需对类进行改造时,则需要修改原有代码(框架),违背了开闭原则。

    • 增加系统复杂度

      在实现深拷贝时需要写较复杂的代码;如果对象之间存在多重嵌套引用,那么每一层对象对应的类必须支持深拷贝,才能实现深拷贝。

    • 避开了构造函数的约束


    4 什么地方使用原型模式

       原型模式的优点决定了其适用的场景,反过来其缺点即是其不适用的场景。原型模式适用场景:


    • 资源优化

      待创建对象资源开销大(数据、内存资源),通过原型模式拷贝已有对象,降低资源开销,提高效率。

    • 待创建对象类型不确定

      待创建对象类型没法静态确认,只能在执行期间确定。

    • 对象副本

      程序运行过程,某个状态下需要一个对象副本;而对象属性有可能在运行过程改变,使用new来创建显然不适合。

    • 简单对象处理

      处理一些比较简单的对象,对象直接区别小,只是某些属性不同;使用原型模式来获得对象省去重新new对象的资源开销,提高效率。

    • 简化复杂的对象创建过程

      一个复杂的对象创建,构造函数需对各种参数初始化,用户需理解每一个参数的含义;使用原型模式直接拷贝一个对象,简化对象复杂的创建过程,减少开发者工作量。

    • 对象被多个对象访问修改

      一个对象被其他多个对象访问,而且各个调用者可能都需要修改该对象,考虑使用原型模块拷贝出多个对象提供调用者访问。

    • 解耦
      一个系统应该独立于它的产品创建、构成和表示时



    具体实例:

    • none

    5 原型模式实现

    实例功能:

      实现一个原型模式实例。

    大体步骤:

    • 抽象原型父类Prototye声明对象拷贝(克隆)接口Clone,已经提供对象属性修改接口SetAddr和属性输出接口ShowAttr
    • 具体原型ConcretePrototye实现抽象原型拷贝接口Clone
    • 用户client调用具体原型对象拷贝接口Clone创建一个对象

    实现过程:

    • 第一步,声明抽象原型类Prototye
    /* prototye.h */
    #ifndef _PROTOTYE_H_
    #define _PROTOTYE_H_
    
    #include <stdbool.h>
    #include <string>
    
    using namespace std;
    
    class Prototye
    {
    public:
    	Prototye(string str);
    	void ShowAttr();
    	void SetAttr(string);
    	virtual Prototye *Clone()=0;
    private:
    	string m_attr;
    };
    #endif
    

    • 第二步,抽象原型类Prototye方法实现
    /* prototye.cpp */
    #include <iostream>
    #include "prototye.h"
    
    using namespace std;
    
    Prototye::Prototye(string str)
    {
    	m_attr = str;
    }
    
    void Prototye::ShowAttr()
    {
    	cout << m_attr << endl;
    }
    
    void Prototye::SetAttr(string str)
    {
    	m_attr = str;
    }
    

    • 第三步,声明具体原型类ConcretePrototye.h,继承抽象父类
    /* concrete_prototye.h */
    #ifndef _CONCRETE_PROTOTYE_H_
    #define _CONCRETE_PROTOTYE_H_
    
    #include <string>
    #include "prototye.h"
    
    class ConcretePrototye:public Prototye
    {
    public:
    	ConcretePrototye(string attr);
    	virtual Prototye *Clone();	
    };
    #endif
    

    • 第四步,具体原型类ConcretePrototye方法实现
    /* concrete_prototye.cpp */
    #include "concrete_prototye.h"
    
    ConcretePrototye::ConcretePrototye(string attr):Prototye(attr)
    {	
    }
    
    Prototye *ConcretePrototye::Clone()
    {
    	ConcretePrototye *p = new ConcretePrototye("");
    	*p = *this;
    	return p;
    }
    

    • 第五步,客户调用不同子类对象实现指定排序功能
    /* client.cpp */
    #include <iostream>
    #include "concrete_prototye.h"
    
    using namespace std;
    
    int main(int argc, char **arv)
    {
    	/* 创建一个原型对象0 */
    	ConcretePrototye *pConcretePrototye0 = new ConcretePrototye("Init");
    
    	cout << "pConcretePrototye0属性:";
    	pConcretePrototye0->ShowAttr();
    	
    	/* 修改原型属性 */
    	pConcretePrototye0->SetAttr("Second");	
    	cout << "pConcretePrototye0属性:";
    	pConcretePrototye0->ShowAttr();
    
    	/* 通过原型对象0拷贝(克隆)一个对象1 */
    	ConcretePrototye *pConcretePrototye1 = (ConcretePrototye*)pConcretePrototye0->Clone();
    	cout << "pConcretePrototye1属性:";
    	pConcretePrototye1->ShowAttr();	/* 对象1和对象0的属性是一样的 */
    
    	delete pConcretePrototye0;
    	delete pConcretePrototye1;
    }
    

    • 最后一步,编写Makefile文件
    VERSION 	=1.00
    CC			=g++
    DEBUG 		=
    CFLAGS		=-Wall
    SOURCES	 	=$(wildcard *.cpp)
    INCLUDES  	=
    LIB_NAMES 	=
    LIB_PATH 	=
    OBJ			=$(patsubst %.cpp, %.o, $(SOURCES))
    TARGET		=client
    
    #links
    $(TARGET):$(OBJ)
    	@mkdir -p output
    	$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
    	@rm -rf $(OBJ)
    	
    #compile
    %.o: %.c
    	$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@
    
    .PHONY:clean
    clean:
    	@echo "Remove linked and compiled files......"
    	rm -rf $(OBJ) $(TARGET) output 
    

    执行结果:

    acuity@ubuntu:/mnt/hgfs/LSW/STHB/design/prototye$ make
    g++    -c -o prototye.o prototye.cpp
    g++    -c -o client.o client.cpp
    g++    -c -o concrtee_prototye.o concrtee_prototye.cpp
    g++  prototye.o  client.o  concrtee_prototye.o   -o output/client1.00
    acuity@ubuntu:/mnt/hgfs/LSW/STHB/design/prototye$ ./output/client1.00 
    pConcretePrototye0属性:Init
    pConcretePrototye0属性:Second
    pConcretePrototye1属性:Second
    acuity@ubuntu:/mnt/hgfs/LSW/STHB/design/prototye$ 
    

    6 原型模式与构造函数

    相同点

    • 功能相同,都是用于对象拷贝,以创建一个对象

    不同点

    • 原理不同

      原型模式通过虚函数多态原理,通过基类指针复制派生类对象。

    • 功能范围不同

      原型模式可以动态获取对象属性;构造函数只能静态创建对象。

    展开全文
  • 本文实例讲述了Android编程设计模式原型模式。分享给大家供大家参考,具体如下: 一、介绍 原型模式是一个创建型的模式。原型二字表明了该模型应该有一个样板实例,用户从这个样板对象中复制出一个内部属性一致的...
  • 原型模式介绍,包括应用场景,优缺点,模式结构,类图 以及 C++代码示例

    更多设计模式参看: 设计模式之模式概述(模式汇总)(C++实现)

    介绍

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

    意图:

    原型模式(Prototype Pattern): 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

    解决问题:

    在运行期建立和删除原型。

    实现概述:

    利用已有的一个原型对象,快速地生成和原型对象一样的实例。

    要点:

    1、实现克隆操作,也就是 clone()

    2、能够隔离类对象的使用者和具体类型之间的耦合关系,要求这些具体类型拥有稳定的接口。

    应用场景:

    (1) 创建新对象成本较大(如一些初始化需要较长时间,占用太多的CPU资源或网络资源),并且新的对象可以通过原型模式对已有对象进行复制来获得,如有必要可稍作修改。

    (2) 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

    生活中场景

    细胞分裂;克隆羊;抄作业

    软件中场景

    JAVA 中的 Object clone() 方法;工作周报、绩效 、邮件等拷贝上次

    优点:

    (1) 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,提高新实例的创建效率。

    (2) 扩展性较好,模式中提供了抽象原型类,具体原型类可根据需要扩展。

    (3) 原型模式提供了简化的创建结构,模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。

    缺点:

    (1) 需要为每一个类配备一个克隆方法,该克隆方法位于一个类的内部,改造已有类时需要修改源代码,违背开闭原则;

    (2) 在实现深克隆时需要编写较为复杂的代码,并且如果对象嵌套很多引用时,为了实现深拷贝每一层嵌套都必须支持深克隆。

    深拷贝与浅拷贝

    浅拷贝:只是增加了一个指针指向已存在的内存地址,如果原地址发生改变,那么浅拷贝出来的对象也会相应的改变。相当于一个箱子有多个钥匙,其中某人打开箱子取走箱子里的东西时,其他人再打开箱子看到的都是空箱子。

    深拷贝:是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。相当有多个箱子每个箱子对应一个钥匙,一个人取走他的钥匙对应的箱子里的东西时,不会对其他人产生影响。

    模式结构

    角色

    • 抽象原型类(AbstractPrototype):规定了具体原型对象必须实现的接口(如果要提供深拷贝,则必须具有实现clone的规定)
    • 具体原型类(ConcretePrototype):从抽象原型派生而来,是客户程序使用的对象,即被复制的对象,需要实现抽象原型角色所要求的接口。
    • 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例

    类图

    在这里插入图片描述

    代码示例

    在已有邮件上修改生成需要发送的新邮件

    GitHub

    Prototype

    抽象原型类(AbstractPrototype)

    /// 抽象原型类(AbstractPrototype)
    class AbstractPrototypeMail {
    public:
        virtual ~AbstractPrototypeMail() = default;
        virtual AbstractPrototypeMail *clone() = 0;
        virtual void showMail() = 0;
        virtual void changeTitle(std::string title) = 0;
        virtual void changeSender(std::string sender) = 0;
        virtual void changeRecipients(std::string rec) = 0;
        virtual void changeBody(std::string body) = 0;
        virtual void changeAtt(std::string name) = 0;
    protected:
        AbstractPrototypeMail() = default;
    };
    

    具体原型类(ConcretePrototype)

    /// 具体原型类(ConcretePrototype)
    class ConcretePrototypeMail : public AbstractPrototypeMail {
    public:
        ConcretePrototypeMail(const std::string &title,const std::string &sender,const std::string &rec,const std::string &body, const std::string &nameAtt=""){
            std::cout << "ConcretePrototypeMail Hello" << std::endl;
            mailTitle = title;
            mailSender = sender;
            mailRecipients = rec;
            mailBody = body;
            if (!nameAtt.empty()) {
                mailAtta = new Attachment();
                mailAtta->changeName(nameAtt);
            }
        }
        ~ConcretePrototypeMail() override {
            std::cout << "ConcretePrototypeMail Bye" << std::endl;
            if (mailAtta!= nullptr) {
                delete(mailAtta);
            }
        }
        AbstractPrototypeMail *clone() override {
            auto *newMail = new ConcretePrototypeMail(mailTitle,mailSender,mailRecipients,mailBody,mailAtta->getName());
            return newMail;
        }
        void showMail() override {
            std::cout << "MailTitle: " << mailTitle << std::endl;
            std::cout << "MailSender: " << mailSender << std::endl;
            std::cout << "MailRecipients: " << mailRecipients << std::endl;
            std::cout << "MailBody: " << mailBody << std::endl;
            std::cout << "MailAttachment: " << mailAtta->getName() << std::endl;
    
        }
        void changeTitle(const std::string title) override {
            mailTitle = title;
        }
        void changeSender(const std::string sender) override {
            mailSender = sender;
        };
        void changeRecipients(const std::string rec) override {
            mailRecipients = rec;
        }
        void changeBody(const std::string body) override {
            mailBody = body;
        }
        void changeAtt(const std::string name) override  {
            if (mailAtta!= nullptr) {
                delete(mailAtta);
            }
            mailAtta = new Attachment();
            mailAtta->changeName(name);
        }
    
    private:
        std::string mailTitle;
        std::string mailSender;
        std::string mailRecipients; /// 按理说 收件人应该有多个 可改为list等其他数据结构,这里采用std::string用于演示
        std::string mailBody;
        Attachment *mailAtta = nullptr;
    };   
    

    附件类

    /// 附件类
    class Attachment {
    public:
        Attachment() {
            std::cout << "Attachment Hello" << std::endl;
        }
        ~Attachment() {
            std::cout << "Attachment Bye" << std::endl;
        }
        void changeName(const std::string &name) {
            nameAtt = name;
        };
        std::string getName() {
            return nameAtt;
        }
    private:
        std::string nameAtt; /// 附件名
    };
    

    测试

    浅拷贝:

    
    int main() {
        /// 用于复用的初始邮件创建
        auto *originalMail = new ConcretePrototypeMail("original_title","original_sender","original_rec","original_body","original_attachment");
        std::cout << "originalMail address: "<< originalMail << std::endl;
        originalMail->showMail();
        /// 浅拷贝
        std::cout << "====浅拷贝====" << std::endl;
        auto *copyMail_A = originalMail;
        copyMail_A->changeTitle("copymail_title");
        copyMail_A->changeSender("copymail_sender");
        copyMail_A->changeRecipients("copymail_rec");
        copyMail_A->changeBody("copymail_body");
        copyMail_A->changeAtt("copymail_attachment");
        std::cout << "====copyMail_A====" << std::endl;
        std::cout << "copyMail_A address: "<< copyMail_A << std::endl;
        copyMail_A->showMail();
        std::cout << "====originalMail====" << std::endl;
        originalMail->showMail();
        delete originalMail;
        return 0;
    }
    

    originalMail的数据也同样被修改了

    深拷贝:

    int main() {
        /// 用于复用的初始邮件创建
        auto *originalMail = new ConcretePrototypeMail("original_title","original_sender","original_rec","original_body");
        originalMail->changeAtt("original_attachment"); 
        std::cout << "originalMail address: "<< originalMail << std::endl;
        originalMail->showMail();
        /// 深拷贝
        std::cout << "====深拷贝====" << std::endl;
        auto *copyMail_A = originalMail->clone();
        copyMail_A->changeTitle("copymail_title");
        copyMail_A->changeSender("copymail_sender");
        copyMail_A->changeRecipients("copymail_rec");
        copyMail_A->changeBody("copymail_body");
        copyMail_A->changeAtt("copymail_attachment");
        std::cout << "====copyMail_A====" << std::endl;
        std::cout << "copyMail_A address: "<< copyMail_A << std::endl;
        copyMail_A->showMail();
        std::cout << "====originalMail====" << std::endl;
        originalMail->showMail();
        delete originalMail;
        delete copyMail_A;
        return 0;
    }
    

    输出

    浅拷贝输出:
    在这里插入图片描述

    深拷贝输出:

    在这里插入图片描述

    个人能力有限,如有错误之处或者其他建议,敬请告知欢迎探讨,谢谢!

    展开全文
  • 设计模式原型模式与享元模式

    千次阅读 2020-01-28 17:29:53
    原型模式是通过给出一个原型对象来指明所创建的对象的类型,然后使用自身实现的克隆接口来复制这个原型对象,该模式就是用这种方式来创建出更多同类型的对象 原型模式是在内存二进制流的拷贝,要被直接new一个对象...

    一、原型模式

    原型模式是通过给出一个原型对象来指明所创建的对象的类型,然后使用自身实现的克隆接口来复制这个原型对象,该模式就是用这种方式来创建出更多同类型的对象

    原型模式是在内存二进制流的拷贝,要被直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点

    1、实现原型模式

    //实现Cloneable接口的原型抽象类Prototype
    public class Prototype implements Cloneable {
        //重写clone()方法
        @Override
        protected Object clone() {
            Prototype prototype = null;
            try {
                prototype = (Prototype) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return prototype;
        }
    }
    
    public class ConcretePrototype extends Prototype{
        public void show (){
            System.out.println("原型模型实现类");
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            ConcretePrototype cp = new ConcretePrototype();
            for (int i = 0; i < 10; ++i) {
                ConcretePrototype cloneCp = (ConcretePrototype) cp.clone();
                cloneCp.show();
            }
        }
    }
    

    要实现一个原型类,需要具备三个条件

    • 实现Cloneable接口:Cloneable接口与序列化接口的作用类似,它只是告诉虚拟机可以安全地在实现了这个接口的类上使用clone()方法。在JVM中,只有实现了Cloneable接口的类才可以被拷贝,否则会抛出CloneNotSupportedException异常
    • 重写Object类中的clone()方法:在Java中,所有类的父类都是Object类,而Object类中有一个clone()方法,作用是返回对象的一个拷贝
    • 在重写的clone()方法中调用super.clone():默认情况下,类不具备复制对象的能力,需要调用super.clone()来实现

    2、原型模式的注意事项

    1)、构造函数不会被执行

    由于Object类的clone()方法的原理是从堆内存中以二进制流的方式进行拷贝,重新分配一个内存块,所以对象拷贝时构造函数不会被执行

    //实现Cloneable接口的原型抽象类Prototype
    public class Prototype implements Cloneable {
        public Prototype(){
            System.out.println("Prototype的构造函数执行了...");
        }
    
        //重写clone()方法
        @Override
        protected Object clone() {
            Prototype prototype = null;
            try {
                prototype = (Prototype) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return prototype;
        }
    }
    
    public class ConcretePrototype extends Prototype{
        public ConcretePrototype(){
            System.out.println("ConcretePrototype的构造函数执行了...");
        }
    
        public void show (){
            System.out.println("原型模型实现类");
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            ConcretePrototype cp = new ConcretePrototype();
            ConcretePrototype cloneCp = (ConcretePrototype) cp.clone();
        }
    }
    

    执行结果如下:

    Prototype的构造函数执行了...
    ConcretePrototype的构造函数执行了...
    

    2)、浅拷贝和深拷贝

    Object类提供的clone()方法只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝

    public class Prototype implements Cloneable {
        private List<String> list = new ArrayList<>();
    
        @Override
        protected Object clone() {
            Prototype prototype = null;
            try {
                prototype = (Prototype) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return prototype;
        }
    
        public void setValue(String value) {
            this.list.add(value);
        }
    
        public List<String> getValue() {
            return this.list;
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            Prototype prototype=new Prototype();
            prototype.setValue("张三");
            Prototype clonePrototype = (Prototype) prototype.clone();
            clonePrototype.setValue("李四");
            System.out.println(prototype.getValue());
        }
    }
    

    执行结果如下:

    [张三, 李四]
    

    深拷贝就是基于浅拷贝来递归实现具体的每个对象

    public class Prototype implements Cloneable {
        private ArrayList<String> list = new ArrayList<>();
    
        @Override
        protected Object clone() {
            Prototype prototype = null;
            try {
                prototype = (Prototype) super.clone();
                //ArrayList实现了Cloneable接口,List没有实现
                this.list = (ArrayList) this.list.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return prototype;
        }
    
        public void setValue(String value) {
            this.list.add(value);
        }
    
        public List<String> getValue() {
            return this.list;
        }
    }
    

    执行结果如下:

    [张三]
    

    3、适用场景

    在一些重复创建对象的场景下,可以使用原型模式来提高对象的创建性能。例如,在循环体内创建对象时,就可以考虑用clone的方式来实现

    二、享元模式

    享元模式是运用共享技术有效地最大限度地复用细粒度对象的一种模式。该模式中,以对象的信息状态划分,可以分为内部数据和外部数据。内部数据是对象可以共享出来的信息,这些信息不会随着系统的运行而改变;外部数据则是在不同运行时被标记了不同的值

    享元模式一般可以分为三个角色,分别为 Flyweight(抽象享元类)、ConcreteFlyweight(具体享元类)和 FlyweightFactory(享元工厂类)。抽象享元类通常是一个接口或抽象类,向外界提供享元对象的内部数据或外部数据;具体享元类是指具体实现内部数据共享的类;享元工厂类则是主要用于创建和管理享元对象的工厂类

    1、实现享元模式

    //抽象享元类
    public interface Flyweight {
        //对外状态对象
        void operation(String name);
    
        //对内对象
        String getType();
    }
    
    //具体享元类
    public class ConcreteFlyweight implements Flyweight {
        private String type;
    
        public ConcreteFlyweight(String type) {
            this.type = type;
        }
    
        @Override
        public void operation(String name) {
            System.out.printf("[类型(内在状态)] - [%s] - [名字(外在状态)] - [%s]\n", type, name);
        }
    
        @Override
        public String getType() {
            return type;
        }
    }
    
    //享元工厂类
    public class FlyweightFactory {
        private static final Map<String, Flyweight> FLYWEIGHT_MAP = new HashMap<>();//享元池,用来存储享元对象
    
        public static Flyweight getFlyweight(String type) {
            if (FLYWEIGHT_MAP.containsKey(type)) {//如果在享元池中存在对象,则直接获取
                return FLYWEIGHT_MAP.get(type);
            } else {//在响应池不存在,则新创建对象,并放入到享元池
                ConcreteFlyweight flyweight = new ConcreteFlyweight(type);
                FLYWEIGHT_MAP.put(type, flyweight);
                return flyweight;
            }
        }
    }
    
    public class Client {
    
        public static void main(String[] args) {
            Flyweight fw0 = FlyweightFactory.getFlyweight("a");
            Flyweight fw1 = FlyweightFactory.getFlyweight("b");
            Flyweight fw2 = FlyweightFactory.getFlyweight("a");
            Flyweight fw3 = FlyweightFactory.getFlyweight("b");
            fw1.operation("abc");
            System.out.printf("[结果(对象对比)] - [%s]\n", fw0 == fw2);
            System.out.printf("[结果(内在状态)] - [%s]\n", fw1.getType());
        }
    }
    

    执行结果如下:

    [类型(内在状态)] - [b] - [名字(外在状态)] - [abc]
    [结果(对象对比)] - [true]
    [结果(内在状态)] - [b]
    

    如果对象已经存在于享元池中,则不会再创建该对象了,而是共用享元池中内部数据一致的对象。这样就减少了对象的创建,同时也节省了同样内部数据的对象所占用的内存空间

    2、适用场景

    享元模式在实际开发中的应用也非常广泛。例如Java的String字符串,在一些字符串常量中,会共享常量池中字符串对象,从而减少重复创建相同值对象,占用内存空间。代码如下:

            String s1 = "hello";
            String s2 = "hello";
            System.out.println(s1 == s2);//true
    

    还有,在日常开发中的应用。例如,线程池就是享元模式的一种实现;将商品存储在应用服务的缓存中,那么每当用户获取商品信息时,则不需要每次都从redis缓存或者数据库中获取商品信息,并在内存中重复创建商品信息了

    单例模式和享元模式都是为了避免重复创建对象,你知道这两者的区别在哪儿吗?

    首先,这两种设计模式的实现方式是不同的。我们使用单例模式是避免每次调用一个类实例时,都要重复实例化该实例,目的是在类本身获取实例化对象的唯一性;而享元模式则是通过一个共享容器来实现一系列对象的共享

    其次,两者在使用场景上也是有区别的。单例模式更多的是强调减少实例化提升性能,因此它一般是使用在一些需要频繁创建和销毁实例化对象,或创建和销毁实例化对象非常消耗资源的类中

    例如,连接池和线程池中的连接就是使用单例模式实现的,数据库操作是非常频繁的,每次操作都需要创建和销毁连接,如果使用单例,可以节省不断新建和关闭数据库连接所引起的性能消耗。而享元模式更多的是强调共享相同对象或对象属性,以此节约内存使用空间

    除了区别,这两种设计模式也有共性,单例模式可以避免重复创建对象,节约内存空间,享元模式也可以避免一个类的重复实例化。总之,两者很相似,但侧重点不一样,假如碰到一些要在两种设计模式中做选择的场景,我们就可以根据侧重点来选择

    参考:

    极客时间专栏《Java性能调优实战》

    《设计模式之禅》

    展开全文
  • 设计模式原型模式

    2017-08-24 13:41:55
    c# 设计模式 原型模式
  • 原型设计模式(Prototype Design Pattern)很有意思, 因为它使用了一种克隆技术来复制实例化的对象. 新对象是通过复制原型实例来创建的. 在这里, 实例是批实例化的具体类.原型设计模式的目的是通过使用克隆来减少实例...
  • 设计模式原型模式的例子,希望对大家有用~~~~~~~~
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高...
  • 1.什么是原型模式 2 参与者 3实例讲解 4使用 Object.create实现原型模式 4.1Object.create()的用法 4.2 用Object.create实现继承 4.2.1 单继承 4.2.2 多继承 4.3 propertyObject参数 4.4 Polyfill 4.5改写...

    目录

    1.什么是原型模式

    2 参与者

    3 实例讲解

    4 使用 Object.create实现原型模式

    4.1 Object.create()的用法

    4.2 用 Object.create实现继承

    4.2.1 单继承

    4.2.2 多继承 

     4.3 propertyObject参数

    4.4 Polyfill

    4.5 改写原型模式实现

    5 总结


    1.什么是原型模式

    原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。 原型模式不单是一种设计模式,也被称为一种编程泛型。 从设计模式的角度讲,原型模式是用于创建对象的一种模式。我们不再关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。在其他语言很少使用原型模式,但是JavaScript作为原型语言,在构造新对象及其原型时会使用该模式。

    2 参与者

     

    原型模式的主要参与者有

    客户端( Client) : 通过要求一个原型克隆自己来创建一个新的对象。

    原型( Prototype) :创建一个接口来克隆自己

    克隆( Clones ) :正在创建的克隆对象

    3 实例讲解

    在示例代码中,我们有一个CustomerPrototype对象,它可以克隆给定原型对象(Customer)。它的构造函数接受一个Customer类型的原型,然后调用克隆方法生成一个新的Customer对象,其对象属性值使用原型对象的值进行初始化。

    这是原型模式的经典实现,但JavaScript可以使用其内置的原型更有效地实现这一功能,后边我们将会修改这一代码

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>JS原型模式:公众号AlbertYang</title>
    	</head>
    	<body>
    	</body>
    	<script>
    		//客户原型类
    		function CustomerPrototype(proto) {
    			this.proto = proto;
    
    			this.clone = function() {
    				var customer = new Customer();
    
    				customer.name = proto.name;
    				customer.age = proto.age;
    
    				return customer;
    			};
    		}
    		//客户类
    		function Customer(name, age) {
    
    			this.name = name;
    			this.age = age;
    
    			this.say = function() {
    				console.info("%c%s", "color:red;font-size:18px", "姓名: " + this.name + ", 年龄: " + this.age);
    			};
    		}
    
    		function run() {
    
    			var proto = new Customer("张三", 18);
    			var prototype = new CustomerPrototype(proto);
    
    			var customer = prototype.clone();
    			customer.say();
    		}
    
    		run();
    	</script>
    </html>
    

    4 使用 Object.create实现原型模式

    在现有的文献里查看原型模式的定义,没有针对JavaScript的,你可能发现很多讲解的都是关于类的,但是现实情况是基于原型继承的JavaScript完全避免了类(class)的概念。我们只是简单从现有的对象进行拷贝来创建对象。

    在新版的ECMAScript5标准中提出,使用Object.create方法来创建指定的对象,其对象的prototype有指定的对象(也就是该方法传进的第一个参数对象),也可以包含其他可选的指定属性。例如Object.create(prototype, optionalDescriptorObjects)。

    4.1 Object.create()的用法

    Object.create()方法用于创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

    语法:

    Object.create(proto[, propertiesObject])

    参数:

    proto新创建对象的原型对象。

    propertiesObject可选。如果没有指定为 undefined,则是要添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。

    返回值:一个新对象,带着指定的原型对象和属性。

    4.2 用 Object.create实现继承

    下面的例子演示了如何使用Object.create()来实现类式继承。这是所有JavaScript版本都支持的单继承。

    4.2.1 单继承

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>JS原型模式:公众号AlbertYang</title>
    	</head>
    	<body>
    	</body>
    	<script>
    		// 父类
    		function Shape() {
    			this.x = 0;
    			this.y = 0;
    		}
    
    		// 父类的方法
    		Shape.prototype.move = function(x, y) {
    			this.x += x;
    			this.y += y;
    			console.info('Shape moved.');
    		};
    
    		// 子类
    		function Rectangle() {
    			Shape.call(this); // call方法用来调用父类Shape的构造函数
    		}
    
    		// 子类继承父类
    		Rectangle.prototype = Object.create(Shape.prototype);
    		//重新指定构造函数
    		Rectangle.prototype.constructor = Rectangle;
            console.log(Rectangle);
    		var rect = new Rectangle();
            
    		console.log(rect);
    		
    		
    		console.log('rect是Rectangle的实例吗?',
    			rect instanceof Rectangle); // true
    		console.log('rect是Shape的实例吗?',
    			rect instanceof Shape); // true
    		rect.move(1, 1); // 输出, 'Shape moved.'
    	</script>
    </html>
    

    4.2.2 多继承 

    如果你希望能继承到多个对象,则可以使用混入的方式。

    function MyClass() {
    	SuperClass.call(this);
    	OtherSuperClass.call(this);
    }
    
    // 继承一个类
    MyClass.prototype = Object.create(SuperClass.prototype);
    // 混合其它类
    Object.assign(MyClass.prototype, OtherSuperClass.prototype);
    // 重新指定constructor
    MyClass.prototype.constructor = MyClass;
    
    MyClass.prototype.myMethod = function() {
    	// 。。。。。
    
    };
    
     

    Object.assign 会把 OtherSuperClass原型上的函数拷贝到 MyClass原型上,使 MyClass 的所有实例都可以使用 OtherSuperClass 的方法。Object.assign 是在 ES2015 引入的,且可用 polyfilled。要支持旧浏览器的话,可用使用 jQuery.extend() 或者 _.assign()。

     4.3 propertyObject参数

    <script>
    	var o;
    
    	// 创建一个原型为null的空对象
    	o = Object.create(null);
    
    	o = {};
    	// 上面的一句就相当于:
    	o = Object.create(Object.prototype);
    
    	o = Object.create(Object.prototype, {
    		// foo会成为所创建对象的数据属性
    		foo: {
    			writable: true,
    			configurable: true,
    			value: "hello"
    		},
    		// bar会成为所创建对象的访问器属性
    		bar: {
    			configurable: false,
    			get: function() {
    				return 10
    			},
    			set: function(value) {
    				console.log("Setting `o.bar` to", value);
    			}
    		}
    	});
    
    
    	function Constructor() {}
    	
    	o = new Constructor();
    	// 上面的一句就相当于:
    	o = Object.create(Constructor.prototype);
    	// 如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码
    
    
    	// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
    	o = Object.create({}, {
    		p: {
    			value: 42
    		}
    	})
    
    	// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
    	o.p = 24
    	console.log(o.p) //42
    
    	o.q = 12
    	for (var prop in o) {
    		console.log(prop); //q
    	}
    
    	delete o.p //false
    	
    	//创建一个可写的,可枚举的,可配置的属性p
    	o2 = Object.create({}, {
    		p: {
    			value: 42,
    			writable: true,
    			enumerable: true,
    			configurable: true
    		}
    	});
    </script>
    

    4.4 Polyfill

    Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。比如说 polyfill 可以让 IE7 使用 Silverlight 插件来模拟 HTML Canvas 元素的功能,或模拟 CSS 实现 rem 单位的支持,或或 text-shadow,或其他任何你想要的功能。

    下边这个 polyfill 涵盖了Object.create主要的应用场景,它创建一个已经选择了原型的新对象,但没有把第二个参数考虑在内。尽管在 ES5 中 Object.create支持设置为[[Prototype]]null,但因为JS以前一些老版本的限制,此 polyfill 无法支持该特性。

    if (typeof Object.create !== "function") {
        Object.create = function (proto, propertiesObject) {
            if (typeof proto !== 'object' && typeof proto !== 'function') {
                throw new TypeError('Object prototype may only be an Object: ' + proto);
            } else if (proto === null) {
                throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
            }
    
            if (typeof propertiesObject !== 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
    
            function F() {}
            F.prototype = proto;
    
            return new F();
        };
    }

    4.5 改写原型模式实现

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>JS原型模式:公众号AlbertYang</title>
    	</head>
    	<body>
    	</body>
    	<script>
    		// 因为不是构造函数(类),所以不用大写
    		var customer = {
    		    name:'',
    			age:'',
    			say: function() {
    				console.info("%c%s", "color:red;font-size:18px", "姓名: " + this.name + ", 年龄: " + this.age);
    			}
    		};
    		
    		function run() {
                // 使用Object.create创建一个新客户
    			var myCustomer = Object.create(customer);
    			myCustomer.name = '张三';
    			myCustomer.age = '18';
    			
    			myCustomer.say();
    		}
    
    		run();
    	</script>
    </html>
    

    5 总结

    原型模式在JavaScript里的使用简直是无处不在,其它很多模式有很多也是基于prototype的,大家使用的时候要注意浅拷贝和深拷贝的问题,免得出现引用问题。

    今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎点赞,评论,转发!!!

    展开全文
  • 设计模式专题之(五)原型模式---设计模式原型模式示例代码(python--c++)
  • 这个是http://blog.csdn.net/dawanganban/article/details/9900539博客中java设计模式的源代码。下载前请先看《设计模式——原型模式》一文。
  • 本文实例讲述了javascript设计模式原型模式原理与应用。分享给大家供大家参考,具体如下: 介绍:在日常的开发过程中,我们经常会利用到前端模板引擎来做页面渲染,因为存在很多页面结构相同,内容不同的场景。...
  • 本文实例讲述了PHP设计模式原型模式Prototype。分享给大家供大家参考,具体如下: 1. 概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以...
  • 《Java设计模式》面向有一定Java语言基础和一定编程经验的读者,重点探讨在Java程序设计中怎样使用著名的23个设计模式。《Java设计模式》的目的是让读者不仅学习怎样在软件设计中使用好设计模式,更重要的是让读者...
  • Prototype:(1)、意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象;(2)、当一个系统应该独立于它的产品创建、构成和表示时,要使用Prototype模式;以及当要实例化的类是在运行时刻指定时,...
  • 本文实例讲述了php设计模式原型模式。分享给大家供大家参考,具体如下: 我们一般用new来新增对象,不过很多时候新增一个对象需要一些工作。而星际里面往往会新增某些类的大量的对象,比如新增很多机枪兵和龙骑。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,204,944
精华内容 881,977
关键字:

原型模式