【学习日志】2022.08.26 C#单例模式 Tostring Utils

知识提纲

C#属性

159b8f1fdedc4d0c9281a2a9294186ab.png

 

C#单例模式 

0.自用超级简单式

namespace ConsoleApp2
{
    //工具类
    class Utils
    {
        private static Utils instance = null;

        public static Utils Instance
        {
            get
            {
                if(instance == null)
                {
                    instance = new Utils();
                }
                return instance;
            }
        }
    }
}

 

1.单线程单例模式

        public sealed class Singleton
        {
            public static Singleton instance = null;
            private Singleton() { }
            public static Singleton Instance
            {
                get
                {
                    if (instance == null)
                        instance = new Singleton();
                    return instance;
                }
            }
        }

实现很简单,理解起来也不难,但是有个致命的缺点:线程不安全,两个线程可能同事检测到 instance==null成立,因为有可能在一瞬间创建两个。其实在多线程运行时,即使已经在内存中创建了实例,但是内存模型并不能保证新的instance能够看见其它线程所创建的实例。因此这种方法不推荐。下面看看线程安全的方法:


2.简单线程安全

 public sealed class Singleton2
        {
            private static Singleton2 instance = null;
            private static readonly object padlock = new object();
 
            private Singleton2() { }
            public static Singleton2 Instance
            {
                get
                {
                    lock(padlock)
                    {
                        if (instance == null)
                            instance = new Singleton2();
                        return instance;
                    }
                }
            }
        }

 变化不大,基于前面的分析,这个只是添加了一个object成员以此来实现锁。这种方法是线程安全的,每个线程要创建实例时,都要先去得锁,然后再判断是否为空,也就是保证多线程运行时,只有一个线程能进行进行实例化,而一旦一个线程实例化后,后面的线程取到锁后,就会发现实例已经创建。但是这个方法也有一个明显的缺点:假设线程足够多,100个吧,每一个线程在进行if(instance==null)判断时,都到等到某一个线程退出后将锁获得。所以会导致性能问题。改进的办法就是多进行以此判断,如果instance==null是FALSE,那自然没必要在等待锁,再去判断一次。


3.双层验证下的多线程安全

 public sealed class Singleton2
        {
            private static Singleton2 instance = null;
            private static readonly object padlock = new object();
 
            private Singleton2() { }
            public static Singleton2 Instance
            {
                get
                {
                    if(null==instance)
                    {
                        lock (padlock)
                        {
                            if (instance == null)
                                instance = new Singleton2();
                            
                        }
                    }
 
                    return instance;
                }
            }
        }

4.更高效的单例模式——饿汉模式

        public sealed class Singleton3
        {
            private static readonly Singleton3 instance = new Singleton3();
 
            static Singleton3() { }
            private Singleton3() { }
 
            public static Singleton3 Instance
            {
                get
                {
                    return instance;
                }
            }
 
 
        }

 正如你看到的,这个似乎比前面两种实现都要简单,它是如何保证线程安全的呢?对于每个AppDomain,在C#中类的实例被构造或者静态成员被引用时,静态构造函数才会执行,而且只执行一次。由于这个类在一加载就被实例化,因此,效率上要比前面实现高的多。

        那为何叫饿汉模式呢?这是因为相对于第2、3的实现方式,Singleton必选被引用一次后才会将自己实例化,这种成为懒汉式;而当下,无论我们在程序中用不用,编译器都会实例化一个对象,所以就成为“饿汉模式”

        那我们看另外一种懒汉模式:

 

5. 懒汉模式——利用嵌套类

public sealed class Singleton
{
    private Singleton()
    {
    }
 
    public static Singleton Instance { get { return Nested.instance; } }
 
    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }
 
        internal static readonly Singleton instance = new Singleton();
    }
}

6. 使用net4之后的Lazy泛型

        在.net4之后,可以使用System.Lazy<T>类型实现迟实例化,你唯一需要做的就是传递一个代理便令给单例类的构造函数,可以用lambda表达式轻松实现:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
 
    public static Singleton Instance { get { return lazy.Value; } }
 
    private Singleton()
    {
    }
}

  上面的代码会隐式的调用LazyThreadSafetyMode.ExecutionAndPublication以实现lazy<Singleton>线程安全模式.

 

public override string Tostring

这个是一个很简单的类,他包含两个property name和Age,这里我们就overrid了ToString的函数,你可以使用任何你想要的方式来重写这个函数,只要return一个string就可以了。

        class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
 
            public override string ToString()
            {
                return String.Format("Name is {0}, Age is {1}", Name, Age);
            }
        }

调用的代码如下: 

Person person = new Person { Name = "Jason", Age = 20 };
Console.WriteLine(person.ToString());

 output:

2020080309224336.png

 

常用工具Utils

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp2
{
    //工具类
    class Utils
    {
        private static Utils instance = null;

        public static Utils Instance
        {
            get
            {
                if(instance == null)
                {
                    instance = new Utils();
                }
                return instance;
            }
        }

        //生成随机数
        private static Random random = new Random();
        public int RandomNum(int a, int b)
        {
            return random.Next(a, b);
        }

        //打印数组的方法
        public static void PrintArray(int[] array)
        {
            for (int i = 0; i < array.Length; i++)
            {
                Console.WriteLine(array[i]);
            }
        }
        public static void PrintArray(int[,] array)
        {

            for (int i = 0; i < array.GetLength(0); i++)
            {
                for (int j = 0; j < array.GetLength(1); j++)
                {
                    Console.WriteLine(array[i, j]);
                }

            }
        }
    }
}

调用

Utils.Instance.RandomNum(1,100);

范例

题目

da4acad30e8f4848955c05ff038ee3ad.png

我的解答


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace mhls
{
    class CharacterManager
    {
        private static CharacterManager instance = null;

        public static CharacterManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new CharacterManager();
                }
                return instance;
            }
        }

        Character[] all = new Character[100];
        int index = 0;
        public Character CreateCharacter(string name, int hp, int attack, int def)
        {
            Character c = new Character(name, hp, attack, def);
            all[index] = c;
            index++;
            return c;
        }
        public void PrintAll()
        {
            for (int i = 0; i < index; i++)
            {
                Character c = all[i];
                Console.WriteLine(all[i]);
            }
        }
    }


    class Character
    {
        public string name;
        //用属性可以简单实现只读属性
        public int attack { get; set; }
        public int def;

        public int hp;

        public Character()
        {
            name = "未知";
        }

        public Character(string name, int hp, int attack, int def)
        {
            this.name = name;
            this.hp = hp;
            this.attack = attack;
            this.def = def;
        }

        public void CostHp(int cost)
        {
            this.hp -= cost;
            if (this.hp <= 0)
            {
                this.hp = 0;
            }
        }

        public bool IsDead()
        {
            return hp <= 0;

        }
        public override string ToString()
        {
            return $"角色:{name} HP:{hp} 攻击力:{attack} 防御力:{def}";
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            Character c1 = CharacterManager.Instance.CreateCharacter("男拳", 100, 15, 1);
            Character c2 = CharacterManager.Instance.CreateCharacter("女拳", 70, 10, 10);
            CharacterManager.Instance.PrintAll();
            Console.WriteLine();
            //战斗过程
            while (!c1.IsDead() && !c2.IsDead())
            {
                if (c1.hp > 20)
                {
                    int cost1 = c1.attack - c2.def;
                    c2.CostHp(cost1);
                    Console.WriteLine($"{c1.name}攻击了{c2.name},{c2.name}损失了{cost1}血量");
                    Console.WriteLine(c1);
                    Console.WriteLine(c2);
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine("男拳血量少于20,触发愤怒被动,攻击力翻倍");
                    int cost2 = 2 * c1.attack - c2.def;
                    c2.CostHp(cost2);
                    Console.WriteLine($"{c1.name}攻击了{c2.name},{c2.name}损失了{cost2}血量");
                    Console.WriteLine(c1);
                    Console.WriteLine(c2);
                    Console.WriteLine();
                }

                if (c2.IsDead())
                {
                    break;
                }
                int cost = c2.attack - c1.def;
                c1.CostHp(cost);

                Console.WriteLine($"{c2.name}攻击了{c1.name},{c1.name}损失了{cost}血量");
                Console.WriteLine(c1);
                Console.WriteLine(c2);
                Console.WriteLine();
            }

            //判断胜负
            if (c1.IsDead())
            {
                Console.WriteLine($"------{c2.name}胜利!------");
                Console.WriteLine();
            }
            else
            {
                Console.WriteLine("女拳第一次死亡,触发复活被动,复活30滴血,继续战斗");
                Character c3 = CharacterManager.Instance.CreateCharacter("女拳", 30, 10, 10);
                Console.WriteLine(c1);
                Console.WriteLine(c3);
                Console.WriteLine();


                while (!c1.IsDead() && !c3.IsDead())
                {
                    if (c1.hp > 20)
                    {
                        int cost3 = c1.attack - c3.def;
                        c3.CostHp(cost3);
                        Console.WriteLine($"{c1.name}攻击了{c3.name},{c3.name}损失了{cost3}血量");
                        Console.WriteLine(c1);
                        Console.WriteLine(c3);
                        Console.WriteLine();
                    }
                    else
                    {
                        Console.WriteLine("男拳血量少于20,触发愤怒被动,攻击力翻倍");
                        int cost4 = 2 * c1.attack - c3.def;
                        c3.CostHp(cost4);
                        Console.WriteLine($"{c1.name}攻击了{c3.name},{c3.name}损失了{cost4}血量");
                        Console.WriteLine(c1);
                        Console.WriteLine(c3);
                        Console.WriteLine();
                    }
                    if (c3.IsDead())
                    {
                        break;
                    }

                    int cost5 = c3.attack - c1.def;
                    c1.CostHp(cost5);

                    Console.WriteLine($"{c3.name}攻击了{c1.name},{c1.name}损失了{cost5}血量");
                    Console.WriteLine(c1);
                    Console.WriteLine(c3);
                    Console.WriteLine();
                }

                if (c1.IsDead())
                {
                    Console.WriteLine($"------{c3.name}胜利!------");
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine($"------{c1.name}胜利!------");
                }
                Console.ReadKey();
            }
        }
    }
}


    

题目

be0d5da44da841df997cc7428871dd80.png

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace shuihu
{
    class Shuihu
    {
        public string name;
        public int capacity;
        public int water { get; set; }
        public int temperature;

        public Shuihu(string name,int capacity,int water,int temperature)
        {
            this.name = name;
            this.capacity = capacity;
            this.water = water;
            this.temperature = temperature;
        }

        public void addwater(int a)
        {
            if(a<(this.capacity- this.water))
            {
                this.water += a;
                Console.WriteLine($"添加{a}毫升的水");
                Console.WriteLine();
            }
            else
            {
                int y = (this.water + a - this.capacity);
                this.water = this.capacity;  
                Console.WriteLine($"添加{a}毫升的水");
                Console.WriteLine("水已注满,溢出" + y + "毫升");
                Console.WriteLine();
            }
        }
        public void pumpwater(int a)
        {
            if (a < this.water)
            {
                this.water -= a;
                Console.WriteLine($"抽出{a}毫升的水");
                Console.WriteLine();
            }
            else
            {
                this.water = 0;
                Console.WriteLine($"杯子已经空了");
                Console.WriteLine();
            }
        }

        public void heatwater(int a)
        {
            if(this.water != 0)
            {
                if (a > this.temperature && a < 100)
                {
                    this.temperature = a;
                    Console.WriteLine($"水温已加热至{a}摄氏度");
                    Console.WriteLine();
                }
                else if (a < this.temperature)
                {
                    Console.WriteLine($"当前水温为{this.temperature}摄氏度,无法降温");
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine($"水温最多加至100摄氏度,当前水温为{this.temperature}摄氏度");
                    Console.WriteLine();
                }
            }
            else
            {
                Console.WriteLine("被子里面没有水,无法加热");
            }
        }

        public override string ToString()
        {
            return $"{name} 容量{capacity} 水量{water} 温度{temperature}";
        }

    }
   class Program
    {

        static void Main(string[] args)
        {
            Shuihu H1 = new Shuihu("小茶杯",100,0,30);
            Console.WriteLine("水杯初始状态");
            Console.WriteLine(H1.ToString());
            Console.WriteLine();

            Console.WriteLine($"请输入加水量____毫升");
            int add = int.Parse(Console.ReadLine());
            H1.addwater(add);
            Console.WriteLine(H1.ToString());
            Console.WriteLine();

            Console.WriteLine($"请输入抽水量____毫升");
            int sub = int.Parse(Console.ReadLine());
            H1.pumpwater(sub);
            Console.WriteLine(H1.ToString());
            Console.WriteLine();

            Console.WriteLine($"请输入目标温度____");
            int tem = int.Parse(Console.ReadLine());
            H1.heatwater(tem);
            Console.WriteLine(H1.ToString());
            Console.WriteLine();
        }
    }
}


    

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值