设计模式:原型模式
时间:2022-07-25
本文章向大家介绍设计模式:原型模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
系列文章回顾
1 概述
原型模式使用原型实例指定创建对象的种类,并且通过拷贝原型对象创建新的对象。原型模式的关键点在于原型实例与实例的复制,实例的克隆分为深拷贝与浅拷贝。
- 浅拷贝:对于字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象与其副本引用同一对象。
- 深拷贝:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
原型模式使用的是深拷贝, 使用原型模式复制对象不会调用类的构造方法。
2 图解
01_Prototype
原型模式包含三种角色:
- Prototype(原型):定义用于复制现有实例来生成新实例的方法。
- ConcretePrototype(具体原型):负责实现复制现有实例并生成新实例的方法。
- Client(使用者):负责使用复制实例的方法生成新实例。
3 优缺点
优点:
- 性能提高,直接拷贝内存里内容比直接新建实例节省资源;
- 简化对象创建,避免了构造函数的约束,不受构造函数的限制直接复制对象;
- 可通过深克隆的方式保存对象的状态,可以辅助实现撤销操作。
缺点:
- 需要为每个类准备一个克隆方法,该方法位于类的内部,当对已有类进行改造时,需要修改原代码,违背了开闭原则;
- 在实现深拷贝时需要写较复杂的代码,如果对象之间存在多重嵌套引用时,为了实现深拷贝,每一层对象对应的类必须支持深拷贝,实现比较麻烦。
4 应用场景
- 资源优化场景:类初始化需要消耗非常多的资源,原型模式避免了此类消耗;
- 性能和安全要求的场景:通过new产生一个对象需要非常繁琐的数据准备或访问权限时,可以使用原型模式;
- 一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以使用原型模式拷贝多个对象供调用者使用;
- 系统要保存对象的状态,而对象的状态变化很小。
5 实例
02_Prototype_UML
5.1 Python 实现
- prototype.py
#-*- coding: utf-8 -*-
'''
原型模式
'''
from copy import copy, deepcopy
class Prototype(object):
"""原型类"""
def __init__(self):
super(Prototype, self).__init__()
def clone(self):
pass
class ConcretePrototype1(Prototype):
"""具体原型类"""
def __init__(self):
print("Create ConcretePrototype1")
def clone(self):
print("Copy ConcretePrototype1...")
return deepcopy(self)
class ConcretePrototype2(Prototype):
"""具体原型类"""
def __init__(self):
print("Create ConcretePrototype2")
def clone(self):
print("Copy ConcretePrototype2...")
return deepcopy(self)
if __name__ == '__main__':
p1 = ConcretePrototype1()
cp1 = p1.clone()
p2 = ConcretePrototype2()
cp2 = p2.clone()
输出结果:
Create ConcretePrototype1
Copy ConcretePrototype1...
Create ConcretePrototype2
Copy ConcretePrototype2...
5.2 C++ 实现
- prototype.h
#ifndef PROTOTYPE_H
#define PROTOTYPE_H
#include <iostream>
using namespace std;
class Prototype
{
public:
virtual ~Prototype() {}
virtual Prototype* clone() const = 0;
protected:
Prototype() {}
};
class ConcretePrototype1 : public Prototype
{
public:
ConcretePrototype1() {
cout << "Create ConcretePrototype1." << endl;
}
ConcretePrototype1(const ConcretePrototype1& other) {
cout << "Copy ConcretePrototype1..." <<endl;
}
~ConcretePrototype1() {}
ConcretePrototype1* clone() const {
return new ConcretePrototype1(*this);
}
};
class ConcretePrototype2 : public Prototype
{
public:
ConcretePrototype2() {
cout << "Create ConcretePrototype2." << endl;
}
ConcretePrototype2(const ConcretePrototype2& other) {
cout << "Copy ConcretePrototype2..." <<endl;
}
~ConcretePrototype2() {}
ConcretePrototype2* clone() const {
return new ConcretePrototype2(*this);
}
};
#endif // PROTOTYPE_H
- main.cpp
#include <iostream>
#include "prototype.h"
using namespace std;
int main()
{
Prototype* p1 = new ConcretePrototype1();
Prototype* cp1 = p1->clone();
Prototype* p2 = new ConcretePrototype2();
Prototype* cp2 = p2->clone();
delete p1;
delete cp1;
delete p2;
delete cp2;
return 0;
}
输出结果:
Create ConcretePrototype1.
Copy ConcretePrototype1...
Create ConcretePrototype2.
Copy ConcretePrototype2...
- Selenium2+python自动化60-异常后截图(screenshot)
- Cisco Packet Tracer 6.0 实验笔记
- kali 2018.1安装教程
- python接口自动化2-发送post请求
- TypeScript 动态创建类
- Java学习笔记【持续更新】
- 互联网协议入门(二)
- 设计模式六大原则(4):接口隔离原则
- 设计模式六大原则(3):依赖倒置原则
- 闲的无聊时候就手动写第一个漏洞扫描工具吧!
- 模拟退火算法从原理到实战【基础篇】
- python接口自动化3-自动发帖(session)
- 平面上给定n条线段,找出一个点,使这个点到这n条线段的距离和最小。
- python接口自动化4-绕过验证码登录(cookie)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 保持 Go 模块兼容
- Go 模块:v2 及更高版本
- 发布 Go Modules
- SRA toolkit下载数据
- 【测试开发-1】基于Springboot+layui实现接口自动化平台
- 【SpringBoot-2】SLF4J+logback进行日志记录
- 【JMeter-3】JMeter参数化4种实现方式
- 【JMeter-1】JMeter安装与接口测试入门
- 【JMeter-2】JMeter接口测试之断言实现
- 【UI自动化-1】UI自动化环境搭建与简单示例
- 【UI自动化-2】UI自动化元素定位专题
- 【UI自动化-3】UI自动化元素操作专题
- maven的安装与使用
- 【Java多线程-1】线程概述与线程创建和使用
- 【Java多线程-2】Java线程池详解