现在有一个需求:
有一个学生入学,记录学生的个人信息我们需要记录2秒(很耗时),因为信息分类整理由不同的老师去记录(很占用资源),同时这个学生需要在很多模块中要用到(全局使用)。比如课程模块,档案模块,班级模块都要记录学生的信息,以便开展以后的教学工作,而且这个学生在入学后,信息将不会再改变。
常见的写法:
创建一个学生类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Student
{
public Student()
{
Thread.Sleep(2000);//构造这个类需要2秒。
Console.WriteLine("这个学生被创建了!");
}
public void Show()
{
Console.WriteLine("我是学生!");
}
}
}
很简单的一个学生类,首先一个构造函数里面的线程挂起了2秒钟,表示学生录入信息需要2秒,然后就一个Show()方法表示学生已经记录成功了。
假设我们只有教师模块,课程模块,班级模块需要记录学生的信息,
再创建3个类分别表示教师模块,课程模块,班级模块。
public class Teacher
{
Student student = new Student();
public void show()
{
student.Show();
Console.WriteLine("我刚入学,刚到课程模块报道,教师模块记录了我的信息");
}
}
public class Grade
{
Student student = new Student();
public void show()
{
student.Show();
Console.WriteLine("我刚入学,刚到课程模块报道,班级模块记录了我的信息");
}
}
public class course
{
Student student = new Student();
public void show()
{
student.Show();
Console.WriteLine("我刚入学,刚到课程模块报道,课程模块记录了我的信息");
}
}
调用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
public delegate void del(int x,int y);
static void Main(string[] args)
{
Student student = new Student();//实例化一个学生
student.Show();//刚入学
Teacher teacher = new Teacher();//实例化了一个老师模块
teacher.show();//学生到老师模块去报道,并记录学生的信息
course course = new course();//实例化了一个课程模块
course.show();//学生到课程模块去报道,并记录学生的信息
Grade Grade = new Grade();//实例化了一个班级模块
Grade.show();//学生到班级模块去报道,并记录学生的信息
Console.WriteLine();
Console.Read();
}
}
}
运行结果:
跟预想的是一样的
解释一下:这个学生类,在刚入学的时候 实例化了一次表示自己已经入学了,然后这个学生来到教师模块,因为这个学生刚入学,教师并不知道这个学生是谁,然后学生自己又实例化了一次告诉教师自己是谁,然后教师帮学生录入信息,然后学生又来到课程模块报道,同样的课程也不知道这个学生是谁,学生又一次的实例化了自己告诉课程自己是谁,课程录入学生信息,然后学生接着去另外的模块报道。
从编程角度上来讲,一般学校的模块会分很多种的,而学生类实例化一次又很耗时,耗资源,如何解决?。
解决思路:学生类被实例化多次的根本原因就是 其他的模块不知道有这个学生存在,导致学生每去一次模块就要介绍一下自己(实例化),别的模块才知道这个学生是谁。如果在学生刚入学的时候(第一次实例化)学校就保存学生的信息然后通知到各个模块,这样不就避免了学生被多次告知模块自己(实例化)是谁了么。
解决办法:
在学生类中(将信息写个牌子挂在脖子上)实例化一个静态全局变量的对象,让模块去访问这个对象(相当于,学生来了之后,模块看学生脖子上的牌子就知道他是谁了),就可以避免再一次实例化对象。
修改代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Student
{
public Student()
{
Thread.Sleep(2000);//构造这个类需要2秒。
Console.WriteLine("这个学生被创建了!");
}
public static Student student = new Student();//创建一个静态的全局变量给其他模块访问
public void Show()
{
Console.WriteLine("我是学生!");
}
}
}
教师类:
public class Teacher
{
Student student = Student.student;//这里就不用再重新New了 直接访问全局变量就行
public void show()
{
student.Show();
Console.WriteLine("我刚入学,刚到教师模块报道,教师模块记录了我的信息");
}
}
运行结果:
效果显然易见,提升了程序的性能。
现在可以抛开例子谈编程。
这种用全局变量的解决思路是可以实现,但是有一个缺陷:
假如编写这个程序的同事离职了,或者不再负责这个项目,让新来的同事跟进;现在又有新需求,需要再添加一个模块,而这位新同事不知道有这么一个全家变量可以使用,他可能就会用上面的常见写法去实例化这个学生类。
通常为了避免这种情况的发生,前辈大牛们就总结了一种办法来避免这种事情的发生,单例模式应运而生。
下面我们将用单例模式来编写学生类。
修改后的学生类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Student
{
private Student()
{
Thread.Sleep(2000);//构造这个类需要2秒。
Console.WriteLine("这个学生被创建了!");
}
private static Student student = null;
static Student()
{
student = new Student();
}
public static Student CreateStudent()
{
return student;
}
public void Show()
{
Console.WriteLine("我是学生!");
}
}
}
功能模块类编写:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Teacher
{
Student student = Student.CreateStudent();
public void show()
{
student.Show();
Console.WriteLine("我刚入学,刚到教师模块报道,教师模块记录了我的信息");
}
}
}
调用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
public delegate void del(int x,int y);
static void Main(string[] args)
{
Student student = Student.CreateStudent();
student.Show();//刚入学
Teacher teacher = new Teacher();//实例化了一个老师模块
teacher.show();//学生到老师模块去报道,并记录学生的信息
course course = new course();//实例化了一个课程模块
course.show();//学生到课程模块去报道,并记录学生的信息
Grade Grade = new Grade();//实例化了一个班级模块
Grade.show();//学生到班级模块去报道,并记录学生的信息
Console.WriteLine();
Console.Read();
}
}
}
输出结果:
程序变得非常的快
总结:
单例类的编写:
1.将构造函数私有化
2.声明一个私有的静态变量
3.编写一个静态的构造函数去实例化类并赋值给这个私有的静态变量
4.编写一个对外公开的公有方法将这个私有变量返回出去,让外部获取这个对象。
单例模式的实现思路:
跟公有全局变量实现思路一样,不同的是单力模型需要把构造函数变为私有的,不能让外部随意的去实例化对象,从而达到程序里只能有一个这样的对象,提升程序的性能。
这里需要说明一点,当构造函数为静态时,编译器会给出一个语法糖,自动控制只会调用一次,而单例模式有3种写法,这里只是最简单而且最常用的写法,有语法糖,所以不用去考虑多线程的问题。
PS:以上是我看完其他文章自己总结出的结论,若有理解错误地方,还请告知 ,谢谢!!!