C#OOP CH04 深入类的方法

本文详细介绍了C#中的类构造函数,包括无参和带参构造函数,以及析构函数的基本概念。探讨了方法重载,特别是构造方法的重载,并通过实例展示了如何使用this关键字。接着,文章讲解了单例模式,对比了懒汉模式和饿汉模式的优缺点,以及如何解决线程安全问题。最后,提出了静态内部类在单例模式中的应用,以实现延迟加载和线程安全的单例模式。
摘要由CSDN通过智能技术生成

C#OOP CH04 深入类的方法

本章目标:

  • 理解并会编写类的构造函数
  • 会实现方法重载
  • 理解类之间的通信

1. 构造函数

构造函数是类中一种特殊的方法,也叫构造方法,或者构造器,或者构造体,函数名与类名相同,不返回任何值,也不能用void修饰,主要完成对象的初始化工作。

构造函数在每次实例化类时 通过new关键字调用

1.1 无参构造函数:

默认情况下,系统会分配给类分配一个无参构造函数,并且没有方法体,用来对成员变量进行初始化操作。

可以自定义一个无参构造函数,在方法体内对类的属性进行初始化操作。

无参构造函数的语法为:

访问修饰符  类名()
{
	//方法体
}

1.2 带参构造函数:

语法为: 参数列表一般用来给类的属性赋值.

访问修饰符  类名(参数列表)
{
	//方法体
}     

注意:

  • 当我们创建一个类时,系统将自动给类分配一个默认的无参构造函数

    而一旦定义了构造函数 系统将不再自动分配构造函数。

    结构与枚举没有构造函数

1.3 析构函数

析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

以C#语言为例,析构函数名也应与类名相同,只是在函数名前面加一个波浪符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。

语法:

~ 类名()
{
    //方法体
}    

2. 方法重载(overload)

同一个类中 方法名相同 参数列表(参数个数,参数类型)不同 称为方法重载。

注意 方法重载与返回值类型无关

2.1 构造方法重载

举例如下:

public SE()
{

}
public SE(int id)
{
    this.ID = id;
}
public SE(int id,String name) 
{
	this.ID = id;
    this.Name = name;
}

// 注意 多个重载的构造函数之间 可以使用 this关键字调用 
// 语法为:
public SE(int id,String name) : this(id)
{
    this.Name = name;
}
> 补充访问修饰符:

C#中的访问修饰符 以及权限

public: 公共访问,不受任何限制

private: 私有访问,只限于本类成员访问,子类和实例都访问不到,类中成员没写修饰符,默认为private

protected: 受保护的,只能在本类或是子类中访问,实例不能访问

internal: 内部访问,只限于在此项目中访问,其他都访问不到 如果类没写访问修饰符,默认为internal

3. 扩展

3.1 软件设计模式之单例模式:

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。

通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例(例如 Windows系统中的回收站)

所以单例模式的要点有三个:

一是 :某个类只能有一个实例;

二是:它必须自行创建这个实例;

三是:它必须自行向整个系统提供这个实例。

设计核心:将构造器私有化,对外提供公有的获取该类实例的方法

3.2 懒汉模式:

所谓懒汉模式,正如其名,比较懒,在类加载的时候并不创建自身实例,采用延迟加载的方式,只有在运行时调用了相关的方法才会被动创建自身的实例。

代码演示如下:

/// <summary>
/// 单例模式之懒汉模式
/// </summary>
public sealed class Singleton
{
    private static Singleton single;
    private Singleton() {}
    public static Singleton GetInstance()
    {
        if(null == single)
        {
            single = new Singleton();
        }
        return single;
    }
}

使用Main方法测试并发情况下,懒汉模式的线程安全问题,代码如下:

static void Main(string[] args)
{
    for (int i = 0; i < 10; i++)
    {
        new Thread(()=>
                   {
                       Console.WriteLine(Singleton.GetInstance().GetHashCode());
                   }).Start();
    }
    Console.ReadLine();
}

控制台输出如图所示:
在这里插入图片描述

从输出结果分析,很明显 , 在多线程下无法正常工作,这也是致命的缺陷。

现在对上面的示例进行修改,因为最简单的方法就是考虑同步,这里采用synchronized实现。

/// <summary>
/// 单例模式之懒汉模式
/// </summary>
public sealed class Singleton
{
    private static Singleton single;
    private static readonly Object obj = new object();
    private Singleton() {}
    public static Singleton GetInstance()
    {
        if(null == single)
        {
            lock (obj)//解决线程并发时 系统创建多个实例的问题
            {
                if (null == single)
                    single = new Singleton();
            }
        }
        return single;
    }
}

以上写法能够在多线程并发环境中很好地工作,并且看起来它也具备了延迟加载的特性。但是很遗憾,这种处理方式效率不高,可以说95%以上的情况都不需要同步。

那么对于线程安全问题,还有另一种解决方式,即饿汉模式。

3.3 饿汉模式:

饿汉模式在类加载的时候就已经完成了初始化操作,所以类加载较慢,但是获取对象的速度很快。由于饿汉模式在类初始化时就完成了实例化,所以它是不存在线程安全问题的。修改以上的代码:

/// <summary>
/// 单例模式之饿汉模式
/// </summary>
public sealed class Singleton
{
    //饿汉式
    private static Singleton single = new Singleton();
    private Singleton() {  }
    public static Singleton GetInstance()
    {
    	return single;
    }
}    

上述代码中修改了GetInstance()方法,直接返回single,而此实例在类加载时就已经自行实例化了。这种方式基于classloader机制,有效避免了多线程的同步问题。

但是,由于导致类加载的原因比较多,而此时单例类ConfigManager在类加载时就实例化,显然没有达到延迟加载的效果。

现在可以对比一下两种方式:

懒汉模式,在类加载时不创建实例,因此类加载速度快,但是运行时获取对象的速度较慢,具备延迟加载的特性,但是又存在线程不安全的问题。

饿汉模式在类加载时就完成初始化,所以类加载较慢,但是获取对象的速度很快。
懒汉模式是“时间换空间”,饿汉模式是“空间换时间”,因为一开始就创建了实例,所以每次使用时直接返回该实例就好了。

在实际开发场景中,实例化单例类很消耗资源,我们希望它可以延迟加载,显然饿汉模式并不能实现。那么我们应该怎么处理呢?

要想让饿汉模式同时具备延迟加载的特性,可以搭配静态内部类进行改造实现。

改造代码如下:

/// <summary>
/// 单例模式之饿汉模式
/// </summary>
public sealed class Singleton
{
    //饿汉式
    private Singleton() {  }
    //使用静态内部类 解决饿汉模式的延迟加载问题
    private static class Single
    {
        internal static readonly Singleton sing = new Singleton();
    }
    public static Singleton GetInstance()
    {
        retunr Single.sing;
    }
}   

总结:

对于单例模式的使用,不管是懒汉模式,饿汉模式,或者静态内部类的方式,根据具体的业务需求而定。反正要遵守一个原则:

在整个程序运行期间,有且仅有一个实例。

若违背这一点,那么即使设计的天花乱坠,也不是单例模式的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值