系列文章目录
前言
原型模式的核心在于复制对象,首先创建一个对象,然后直接基于内存二进制流进行复制,不需要在耗时的去对象初始化的过程,针对于大批量操作以及复杂类的实例化性能提升很多,
一、原型模式(ProtoType)
定义某个对象为一个原型,根据这个原型来创建对象,减少了初始化的过程,性能提升很多。
二、应用场景
- 针对大量get,set复制的情况,创建对象初始化的过程,可以提升效率。
- 创建对象成本较大时,使用原型模式,比如建造者模式中,多个对象组合成一个大的结构。
- 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性,
- 系统中大量使用该类对象,且各个调用者都需要给他的属性重新复制时,
三、角色分析
- 客户(Client):客户类提出创建对象的请求
- 抽象原型(IProtoType):规定复制接口
- 具体原型(ConcreteProtoType):被复制的对象。
四、实现
1、基本实现
原型模式的基本实现方式。
2、原型注册表实现
提供了一种访问常用原型的简单方法, 其中存储了一系列可供随时复制的预生成对象。 最简单的注册表原型是一个 名称 → 原型的哈希表。 但如果需要使用名称以外的条件进行搜索, 你可以创建更加完善的注册表版本。
二、使用步骤
1.通用原型使用方式
通用原型使用方式
/// <summary>
/// 实体类
/// </summary>
public class CommonProtoType
{
public CommonProtoType(int age, string name, bool sex, string phone, string emain, string address, string password)
{
this.age = age;
this.Name = name;
this.sex = sex;
this.Phone = phone;
this.email = email;
this.address = address;
this.password = password;
}
public int age { get; set; }
public string? Name { get; set; }
public bool sex { get; set; }
public string? Phone { get; set; }
public string? email { get; set; }
public string? address { get; set; }
public string? password { get; set; }
//获取克隆的新对象
public CommonProtoType GetCloneNewObject()
{
return (CommonProtoType)this.MemberwiseClone();
}
}
/// <summary>
/// 客户端
/// </summary>
public class Client
{
public void testDemo()
{
var protoType = new CommonProtoType(10, "kenny", sex: true, phone: "123412341234", emain: "kenny@abp.com", address: "test.Kenny", password: "asdfasdf");
var cloneProtoType = protoType.GetCloneNewObject();
cloneProtoType.age = 20;
Console.WriteLine(JsonConvert.SerializeObject(protoType));
Console.WriteLine(JsonConvert.SerializeObject(cloneProtoType));
}
}
运行结果
{"age":10,"Name":"kenny","sex":true,"Phone":"123412341234","email":null,"address":"test.Kenny","password":"asdfasdf"}
{"age":20,"Name":"kenny","sex":true,"Phone":"123412341234","email":null,"address":"test.Kenny","password":"asdfasdf"}
2.原型注册表实现
代码如下(示例):接上面CommonProtoType实体类,增加下面仓库管理以及仓库客户端类。
/// <summary>
/// 仓库管理类
/// </summary>
public class ProtoTypeRepository
{
public static Dictionary<string, object> repository = new Dictionary<string, object>();
public static void insert(string key, object value)
{
repository.Add(key, value);
}
public static object getValueByKey(string key)
{
return repository.Where(p => p.Key.Equals(key)).FirstOrDefault().Value;
}
}
/// <summary>
/// 仓库客户端
/// </summary>
public class repositoryClient
{
public void testDemo()
{
Console.WriteLine("第一次创建对象的实例");
var protoType = new CommonProtoType(10, "kenny", sex: true, phone: "123412341234", emain: "kenny@abp.com", address: "test.Kenny", password: "asdfasdf");
Console.WriteLine("将对象的实例保存到仓库");
ProtoTypeRepository.insert("CommonProtoType", protoType);
Console.WriteLine("需要使用时从仓库读取出对应的实例,然后克隆出新的实例");
var outObject = (CommonProtoType)ProtoTypeRepository.getValueByKey("CommonProtoType");
var newObject=outObject.GetCloneNewObject();
Console.WriteLine("得到新实例修改值");
newObject.age = 20;
Console.WriteLine(JsonConvert.SerializeObject(protoType));
Console.WriteLine(JsonConvert.SerializeObject(outObject));
Console.WriteLine(JsonConvert.SerializeObject(newObject));
}
}
输出内容
第一次创建对象的实例
将对象的实例保存到仓库
需要使用时从仓库读取出对应的实例,然后克隆出新的实例
得到新实例修改值
{"age":10,"Name":"kenny","sex":true,"Phone":"123412341234","email":null,"address":"test.Kenny","password":"asdfasdf"}
{"age":10,"Name":"kenny","sex":true,"Phone":"123412341234","email":null,"address":"test.Kenny","password":"asdfasdf"}
{"age":20,"Name":"kenny","sex":true,"Phone":"123412341234","email":null,"address":"test.Kenny","password":"asdfasdf"}
总结
优点:
- 针对于需要频繁创建对象的方法可以有效的提高运行效率,减少对象初始化时间。
缺点:
- 需要为每个可以被克隆的类提供一个克隆方法。
- clone方法位于类内部,当对已有代码进行改造的时候,需要修改代码,违背了开闭原则。
- 当不适用时仓库原型模式会长期占用内存。