单例模式
整个进程有且只有一个实例。该类负责创建自己的对象,同时确保只有一个对象被构建
单例模式可以通过三种形式去实现
方法1:
public class SingletonPattern
{
private static SingletonPattern _Instance = null;
private static readonly object _InstanceLock = new object();
//关闭初始化入口
private SingletonPattern()
{
/*
*
* 业务代码
* **/
}
/// <summary>
/// 入口,有且只能初始化一次
/// </summary>
/// <returns></returns>
public static SingletonPattern CreateSingletonPattern()
{
//双检锁--对象已经实例化之后,不再等待锁
if (_Instance == null)
{
lock (_InstanceLock)
{
if (_Instance == null)
{
_Instance = new SingletonPattern();
}
}
}
return _Instance;
}
}
方法2:静态构造函数,在程序第一次使用这个类型之前,由CLR调用且只调用一次
/// <summary>
/// 静态构造函数,在程序第一次使用这个类型之前,由CLR调用且只调用一次
/// 非常适合做初始化
/// </summary>
static SingletonPatternSecond()
{
_Instance = new SingletonPatternSecond();
}
/// <summary>
/// 入口,有且只能初始化一次
/// </summary>
/// <returns></returns>
public static SingletonPatternThird CreateSingletonPattern()
{
return _Instance;
}
方法3:静态字段,在程序第一次使用这个类型之前,由CLR调用且只调用一次
/// <summary>
/// 静态字段,在程序第一次使用这个类型之前,由CLR调用且只调用一次
/// </summary>
private static SingletonPatternThird _Instance = new SingletonPatternThird();
/// <summary>
/// 入口,有且只能初始化一次
/// </summary>
/// <returns></returns>
public static SingletonPatternThird CreateSingletonPattern()
{
return _Instance;
}
这三个的优先级分别是 静态字段>静态方法>双检锁
单例分为懒汉式和饿汉式,其中,静态字段静态方法为饿汉式,双检锁为懒汉式
懒汉式(双检锁) 除非主动调用 CreateSingletonPattern()方法,否则不会实例化 ,在没有使用时,可以延迟实例化
饿汉式,只要使用了该类型,都会实例化对象
————————————————————————————————————————————————————————————
单例模式的应用场景
线程池、数据库连接池、配置文件对象、IOC容器实例缓存等,需要单例
现如今,容器的流行逐渐淡化了单例,在代码中能不使用单例就不使用单例设计模式
————————————————————————————————————————————————————————————
原型模式
原型模式是用于创建重复的对象,同时又能保证性能。他是专门用来批量生产对象的!
/// <summary>
/// 入口,有且只能初始化一次
/// </summary>
/// <returns></returns>
public static PrototypeClass CreateSingletonPattern()
{
//内存复制,将单例模式变为原型模式
PrototypeClass instance = (PrototypeClass)_Instance.MemberwiseClone();
return instance;
}
通过MemBerwiseClone 方法,进行内存复制,提高了实例化的性能,又可以创建重复的对象,鱼和熊掌兼得
但是原型模式需要注意的是,引用类型是没有办法通过“浅复制”的方式实现的
可以通过上面写好的进行以下修改
public static PrototypeClass CreateSingletonPattern()
{
//内存复制,将单例模式变为原型模式
PrototypeClass instance = (PrototypeClass)_Instance.MemberwiseClone();//拷贝引用
instance.testClass = new TestClass() {
Id = _Instance.testClass.Id,
TestDescription = _Instance.testClass.TestDescription
};//还可以通过序列化反序列化的方式做深拷贝
return instance;
}
深拷贝:在CreateSingletonPattern() 方法中,将引用类型初始,将引用类型的值进行赋值,从而实现自定义类(引用类型)的拷贝
也可以通过序列化、反序列化的方式做深拷贝,需要将拷贝的对象转换成二进制的形式,再转回原类型,这样会比较占有资源内存,这里就不再赘述。
string类型也是引用类型,为什么没有特殊处理?
因为string类型是不可变的,string类型在内存中,如果想重新给这个string变量赋值,则这个string变量会在内存中重新开辟一个新空间
,用于存储新的值
string类型为什么不可变?
不可变的原因是 为了避免内存的频繁移动 然后又开启了 享元模式
总结
原型模式是为了批量生产重复对象,又能保证性能的一种设计模式。
创建型设计模式—— 花样new
关注对象的创建
结构性设计模式——包一层
关注类与类之间的关系,组合优于继承,例如 A里面有个B,调用A完成调用B ,所以就是包一层
行为型设计模式—— 甩锅
关注的是对象和行为的分离,对象和方法到底放在那里,把不稳定的东西丢给别人管理,所以就是甩锅
————————————————————————————————————————————————————————————
设计模式的缺陷
结构性、行为型、大部分的创建型,都是靠抽象来完成扩展性
因为类是静态的,写好了就固定了,想扩展,只能靠抽象-细节的替换
OOP想拓展,基本都靠抽象——OOP的困境
AOP面向切面编程 – 可以在不破坏封装的前提下,去扩展通用功能
————————————————————————————————————————————————————————————
设计模式不是单一使用的,而是融合使用,扬长避短。
设计模式就那么几个核心套路,解决问题时不要拘泥于招数,直接上套路解决完了,再看是属于什么模式
不推荐过度设计!