C#23中设计模式——单例模式(创建型模式)

现在有一个需求:

有一个学生入学,记录学生的个人信息我们需要记录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:以上是我看完其他文章自己总结出的结论,若有理解错误地方,还请告知 ,谢谢!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值