【设计模式】单例模式(Windows版)
01、⽬录
⽬录
02、浅谈设计模式
设计模式(Design Pattern):是⼀套被反复使⽤、多数⼈知晓的、经过分类编⽬的、代码设计经验的总结,使⽤设计模式是为了可重⽤代码、让代码更容易被他⼈理解并且保证代码可靠性
站在巨⼈的肩膀上处理眼前的问题,这就是设计模式的初衷!
关于设计模式,⼴为⼈知的有23种,今天聊聊第⼀种,单例模式。
对于初学者,特别是像我这种应届毕业⽣,⼯作经验也没有,⾯向对象的思想也是马马虎虎,好像懂了,⼜好像没懂的⼈。学习设计模式,可能就会有⼀些效果,怎么说呢?
我们把编程⽐喻为武侠来说。
如果⼀个⼈,除开内功⽽谈,招式就成为了唯⼀的评判标准。这⾥⾯的内容⾃然就是编程的经验与编程
功底,这个是没有捷径可⾛的,只能⽤时间来累积,⽽招式,就是那些形如设计模式、STL、模版和⼀些成熟的框架等等。
设计模式,对于我⽽⾔,其实也是学了⼀些,但是从未⽤过,导致知识的遗忘,所以,今天就当做是温故,⼀起看看吧!
如何判断是否掌握了设计模式,曾经在某云的公开课上看过⼀讲国外的⼤⽜讲的设计模式,但凡能做到“⼿中⽆模式,⼼中有模式”,设计模式便已是⼤成。
何以,此⽬标!
03、⾯向对象基础
在开始之前,我先唠叨⼀下⾯向对象的基础!
1、⾯向对象的三⼤特征
2、⾯向对象中类与类的关系
3、⾯向对象七⼤原则
《23种设计模式》
创建型(5种):主要⽤于处理对象的创建,实例化对象: 单例,建造者,原型,⼯⼚⽅法,抽象⼯⼚
结构型(7种):处理类或对象间的组合:适配器,装饰者,结合,桥接,外观,享元,代理
⾏为型(11种):描述类或对象怎样进⾏交互和职责分配:策略,观察者,迭代器,命令,备忘录,中介者,解释器,访问者,责任链,状态,模板⽅法
3.1 ⾯向对象三⼤特征
1. 封装(Encapsulation)
隐藏对象的具体实现细节,通过共有⽅法暴露对象的功能。内部结构可以⾃由修改,同时可对成员进⾏更加精确的控制 (⽐如在setter ⽅法中加值合法判断)
2. 继承(Inheritance)
使⽤已经存在的类作为⽗类(基类),在此基础上建⽴新的类叫做⼦类(派⽣类),C++⽀持单继承
、多继承。但是C++建议单继承,避免使⽤多继承,因为类的关系越复杂,出错的⼏率也就越⼤,化简为繁才是编程最核⼼的内容。
2.1、⼦类拥有⽗类⾮private的属性与⽅法
2.2、构造⽅法只能调⽤,不能实现,⼦类默认调⽤⽗类的⽆参构造⽅法
2.3、.慎⽤继承,要考虑是否需要从⼦类向⽗类进⾏向上转型!
3. 多态(Polymorphism)
调⽤相同的⽅法(接⼝),产⽣不同的实现(结果),这种现象叫做多态。
多态分为两类:
运⾏时多态:继承 + ⽅法重写 + 向上转型(⽗类引⽤指向⼦类对象)
编译时多态:⽅法重载
我没记错,在C++重载那章是由说过,详细介绍过这两种的区别!
3.2 ⾯向对象中类与类的关系
⼝诀:鸡湿⾐冠剧组(继承,实现,依赖,关联,聚合,组合)
继承和实现就不说了,后⾯四个只是 语意层次 的区别
两个类的相关程度,依赖 < 关联 < 聚合 < 组合
依次的UML类图标记:
继承/泛化(Generalization):
⼦类
⽗类
实现(Realization):
实现类
接⼝
依赖(Dependency):
不持有引⽤,具体表现:局部变量,函数参数, 返回值使⽤
依赖类,⽐如⼤佬依赖于递茶⼩弟;
关联(Association):持有引⽤,具体表现:成员变量, 箭头指向被关联类,可双向,⼀对多或多对多:
聚合(Aggregation):成员变量,关联是处于同⼀层次的,⽽聚合则 是整体和局部层次的,⽐如:社团 和 ⼩弟,另外即使没有了社团, ⼩弟们依旧可以到别的地⽅搞事情。
组合(Composition):与聚合类似,程度更加强烈,共⽣死,组合类 负责被组合类的⽣命周期,⽐如: 社团 和 ⼤佬,如果没了社团, ⼤佬也就就不能存在了。
PS:图⽚来源⽹络,侵权即删!
3.3 ⾯向对象七⼤原则
单⼀职责原则(Single Responsibility Principle) :每⼀个类应该专注于做⼀件事情。 即:⾼内聚,低耦合。
开闭原则(Open Close Principle) ⼀个对象对扩展开放,对修改关闭。即:对类的改动是通过增加代码进⾏的,⽽不是修改现有代码。
⾥⽒替换原则(Liskov Substitution Principle) 在任何⽗类出现的地⽅都可以⽤它的⼦类来替代。
依赖倒置原则(Dependence Inversion Principle) 要依赖于抽象,不要依赖于具体实现。
接⼝隔离原则(Interface Segregation Principle) 应当为客户端提供尽可能⼩的单独的接⼝,⽽不是提供⼤的总的接⼝。
迪⽶特原则(Law Of Demeter) ⼀个对象应当尽量少地与其他对象之间发⽣相互作⽤,使得系统功能模块相对独⽴。
组合/聚合复⽤原则(Composite/Aggregate Reuse Principle)
尽量使⽤组合/聚合的⽅式,⽽不是使⽤继承。
基础介绍完了,就直接进⼊主题吧!单例模式
04、设计模式——单例模式
单例模式:顾名思义,只有⼀个实例化的模式,作⽤就是保证对象的唯⼀性。
应⽤场景:
1、避免创建多个实例浪费资源。
2、避免多个实例因为多次调⽤出现错误。
3、⼀般写⼯具类、线程池、缓冲、数据库会⽤到。
套路(三个要点):
1、私有化构造函数,防⽌外部调⽤。
2、私有化本类的静态成员对象指针,并在类外初始化(重点)
3、提供公有的⽅法将指针给外⾯。
分类:饿汉与懒汉
前者在类装载时就实例化,后者只有在第⼀次被使⽤时才实例化。 (饿汉的优点是避免线程同步问题,缺点是即使没⽤到这个实例还是会加载) (懒汉的优点是实现了懒加载,但需要解决线程安全问题!)
4.1 饿汉模式
//C++代码:
//未实现懒加载
#include <iostream>
using namespace std;
class Cain
{
private:
Cain(){cout <<"单例创建成功...."<< endl;}//私有化默认构造
~Cain()
{
//析构函数
if(m_Cain !=NULL)
{
delete m_Cain;
m_Cain ==NULL;
}
}
private:
static Cain* m_Cain;
public:
static Cain*GetCain()//提供公有⽅法,⾄于为啥⽤static,请看C++分栏,static关键字{
if( m_Cain ==NULL)
{
m_Cain =new Cain;
}
return m_Cain;
}
};
//类外初始化静态成员变量
Cain* Cain::m_Cain =new Cain;
int main()
{
//获取单例指针对象
Cain* p = Cain::GetCain();
Cain* p1 = Cain::GetCain();
/*
if(p != NULL)
{
cout << "单例创建成功...." << endl;
}
else
{
cout << "单例创建失败....." << endl;单例模式的几种实现方式
}
*///上⾯这种写法不直观,应该直接在构造⾥写
//这样做线程是安全的
system("pause");
return0;
}
4.2 懒汉模式
这么写,单线程下运⾏,⼀点问题没得
第⼀次:没有就new ⼀个给你,第⼆次,有了,就直接返回给你。
但是,多线程就有问题了。
//单线程下:C++代码:
//实现懒加载,线程不安全
#include <iostream>
using namespace std;
class Cain
{
private:
Cain(){};//私有化默认构造
~Cain()
{
//析构函数
if(m_Cain !=NULL)
{
delete m_Cain;
m_Cain ==NULL;
}
}
private:
static Cain* m_Cain;
public:
static Cain*GetCain()//提供公有⽅法,⾄于为啥⽤static,请看C++分栏,static关键字
{
if( m_Cain ==NULL)
{
m_Cain =new Cain;
}
}
};
//类外初始化静态成员变量
Cain* Cain::m_Cain =new Cain;
int main()
{
//这样做线程是安全的
system("pause");
return0;
}
多线程下:如果两个线程同时调⽤这个GetCain();
问题来了,同时访问,都是为NULL ,所以,两个都进⼊new,然后,返回两个实例化对象指针。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论