单例模式
先看个例子:
场景目标:点击按钮打开指定的窗口2。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 fm2 = new Form2();
fm2.Show();
}
}
但是这样实现有一个问题,每次点击按钮都会打开一个新的窗口2。会产生很多个窗口2,与我们预期只想要打开指定的窗口2,目标不符。
这个时候就需要单例模式:只有一个实例。
怎么做?
第一步:构造函数私有化。
构造函数就是为了初始化对象。相当于Python中__init__函数。此处我们每次点击按钮都会触发new Form2()这个构造函数来新建一个窗口。所以首先想到的是将构造函数私有化。
按【F12】转到Form2这个类,将public修改为private。
public partial class Form2 : Form
{
//public Form2()
private Form2()
{
InitializeComponent();
}
}
第二步:提供一个静态方法,返回我们需要的对象。
但是此时有一个新的问题产生,转为私有方法之后,form1里面就无法访问到了,这样一个都创建不了了。所以为了让form1访问到,新创建一个静态方法,将form2对象返回。
为什么是静态?
因为构造函数私有了,就无法外部实例化,只能通过类名静态访问来直接调用这个新方法。所以方法是静态的,返回的是form2对象。静态方法只能调用静态属性。
静态成员只在程序编译时就分配空间了。
无论多少个实例对象,都只有一份静态数据的拷贝。静态成员变量属于类所有,所有对象共享。
***********************为什么不能动态?************************************这点对理解动态静态至关重要********************
静态方法是在类中使用staitc修饰的方法,在类定义的时候已经被装载和分配。
而非静态方法是不加static关键字的方法,在类定义时没有占用内存,只有在类被实例化成对象时,对象调用该方法才被分配内存。
所以说不实例化,动态方法,外部没法直接用到。类内可以自己调用转手给静态方法调用出去。
所以这个方法:必须是public的,否则外部还是没法访问,然后是static的,不实例化也能访问。类型是Form2的。方法。
public partial class Form2 : Form
{
//public Form2()
private Form2()
{
InitializeComponent();
}
//改变从这里开始
public static Form2 GetSingle()
{
Form2 fm2 = new Form2();
return fm2;
}
}
此时在form1代码中点击按钮之后,调用新方法来实现操作:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Form2 fm2 = new Form2();
// 这里改变了。
Form2 fm2 = Form2.GetSingle(); // new Form2();
fm2.Show();
}
}
但是操作之后发现,还是没有达到预期效果。
分析原因,因为还是没有根本改变:每次点击按钮新建一个窗口这个本质。
第三步:创建一个单例对象字段
肯定少了关键的一步:唯一性。前面都是铺垫,都在为唯一性铺路。怎么唯一性。类里面有什么唯一?值单一。首先想到字段。
// 全局唯一的单例。字段。
public static Form2 FrmSingle;
这样在新函数方法中,返回这个form2目标类型的字段对象就可以了。
public partial class Form2 : Form
{
// 全局唯一的单例。字段。
public static Form2 FrmSingle;
//public Form2()
private Form2()
{
InitializeComponent();
}
public static Form2 GetSingle()
{
//这里要改变
FrmSingle = new Form2();
return FrmSingle;
}
}
但是此时还是无法限制个数:
为此需要增加窗体对象个数判断。引入条件判断。检测对象字段状态,有值了就不要赋值了。
修改为:字段初始化为null,如果为null,则建窗口2,否则不操作,返回原来的form2。
public partial class Form2 : Form
{
// 全局唯一的单例。字段。
public static Form2 FrmSingle=null;
//public Form2()
private Form2()
{
InitializeComponent();
}
//改变从这里开始
public static Form2 GetSingle()
{
if (FrmSingle==null)
{
FrmSingle = new Form2();
}
return FrmSingle;
}
}
总结一:
一、静态方法只能访问静态方法和静态成员。
二、非静态方法要被实例化才能被静态方法调用。
总结二:
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建(类内 创建 目标对象 字段)这个实例的一种模式。
总结三:
应用场景:不需要实例化,特指就是那个。
1、一个班级只有一个班主任。
2、只有一台激光雷达、驱动马达、一个摄像头。
3、一台电脑两台打印机一个文档。
这种场景,最好的做法,直接将字段和方法全写成静态的,类名直接调用方法就成了。
单一模块,反复多次调用,写成静态类和方法。因为Console.WriteLine()常用,所以写成静态方法。免得每次用之前还要实例化。
C++中的静态成员实现单例模式
class Printer{
public:
// 通过静态方法返回静态单例。
static Printer* getInstance(){ return pPrinter;}
void PrintText(string text){
cout << "打印内容:" << text << endl;
cout << "已打印次数:" << mTimes << endl;
cout << "--------------" << endl;
mTimes++;
}
private:
// 将 默认构造函数 和 拷贝构造函数 私有化,防止外部创建实例。
Printer(){ mTimes = 0; }
Printer(const Printer&){}
private:
static Printer* pPrinter;
int mTimes;
};
Printer* Printer::pPrinter = new Printer; // 静态变量类外初始化
void test(){
Printer* printer = Printer::getInstance();
printer->PrintText("离职报告!");
printer->PrintText("入职合同!");
printer->PrintText("提交代码!");
}
待总结:
5. 单例模式 — Graphic Design Patterns