面向對象23種設計模式系列(一)- 創建型設計模式

来源:https://www.cnblogs.com/xyh9039/archive/2020/07/12/13258500.html
-Advertisement-
Play Games

本系列將和大家分享面向對象23種設計模式中常用的幾種設計模式,本章主要簡單介紹下創建型設計模式。 ...


本章是面向對象23種設計模式系列開篇,首先我們來看下什麼是設計模式?

面向對象23種設計模式

  1、面向對象語言開發過程中,遇到的種種場景和問題,提出瞭解決方案和思路,沉澱下來就變成了設計模式。

  2、解決具體問題的具體招數---套路---站在前輩的肩膀上。

  3、沒有什麼設計模式是完美無缺的,一種設計模式就是解決一類問題,通常設計模式在解決一類問題的同時,還會帶來別的問題,我們設計者要做的事兒,就是要揚長避短,充分發揮長處!

設計模式可以大概分為三大類

  1、創建型設計模式:關註對象的創建。

  2、結構型設計模式:關註類與類之間的關係。

  3、行為型設計模式:關註對象和行為的分離。

我們要做的就是學習核心套路,這裡就不做過多的描述,如果有機會會通過具體例子再和大家分享。下麵我們正式進入本章主題。

創建型設計模式:關註對象的創建。(5個)

1、單例模式(Singleton Pattern)

單例模式:

  就是限制了對象的創建,重用了對象。保證進程中,某個類只有一個實例。

  即使是單例,變數也不是線程安全的,單例不是為了保證線程安全。

  單例的好處就是單例,就是全局唯一的一個實例。

  應對一些特殊情況,比如資料庫連接池(內置了資源) ,全局唯一號碼生成器。

  單例可以避免重覆創建,但是也會常駐記憶體,除非是真的有必要,否則就不要使用單例。

1.1、單例模式經典寫法(懶漢式)

using System;
using System.Threading;

namespace SingletonPattern
{
    /// <summary>
    /// 懶漢式單例模式(經典寫法)
    /// 單例類:一個構造對象很耗時耗資源類型。
    /// </summary>
    public class Singleton
    {
        /// <summary>
        /// 構造函數耗時耗資源
        /// </summary>
        private Singleton()
        {
            long lResult = 0;
            for (int i = 0; i < 10000000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(2000);
            Console.WriteLine("{0}被構造一次", this.GetType().Name);
        }

        /// <summary>
        /// 全局唯一靜態  重用這個變數
        /// volatile 促進線程安全 讓線程按順序操作
        /// </summary>
        private static volatile Singleton _singleton = null;

        /// <summary>
        /// 引用類型對象
        /// </summary>
        private static readonly object lockSingleton = new object();

        /// <summary>
        /// 公開的靜態方法提供對象實例
        /// </summary>
        /// <returns>
        /// </returns>
        public static Singleton CreateInstance()
        {
            if (_singleton == null) //_singleton已經被初始化之後,就不要進入鎖等待了
            {
                //保證任意時刻只有一個線程進入lock範圍
                //也限制了併發,尤其是_singleton已經被初始化之後,故使用了雙if來解決併發限制問題
                lock (lockSingleton)
                {
                    //Thread.Sleep(1000);
                    //Console.WriteLine("等待鎖1s之後才繼續。。。");
                    if (_singleton == null) //保證只實例化一次
                    {
                        _singleton = new Singleton();
                    }
                }
            }

            return _singleton;
        }

        public int iTotal = 0;

        /// <summary>
        /// 既然是單例,大家用的是同一個對象,用的是同一個方法,那還會併發嗎  還有線程安全問題嗎?
        /// 即使是單例,變數也不是線程安全的,單例不是為了保證線程安全。
        /// </summary>
        public void Increment()
        {
            //lock (lockSingleton)
            //{
            this.iTotal++;
            //}
        }

        public static void Show()
        {
            Console.WriteLine(_singleton.iTotal);
        }
    }
}

使用如下:

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

namespace SingletonPattern
{
    /// <summary>
    /// 為什麼要有單例設計模式?
    /// 構造對象耗時耗資源,很多地方都需要去new, 這個方法 其他方法  其他類
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                {
                    //保證進程中,某個類只有一個實例
                    //1 構造函數私有化 避免別人還去new
                    //2 公開的靜態方法提供對象實例
                    //3 初始化一個靜態欄位用於返回 保證全局都是這一個
                    Singleton singleton1 = Singleton.CreateInstance();
                    Singleton singleton2 = Singleton.CreateInstance();
                    Singleton singleton3 = Singleton.CreateInstance();
                    Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
                    Console.WriteLine(object.ReferenceEquals(singleton3, singleton2));
                }

                {
                    List<Task> tasks = new List<Task>();
                    for (int i = 0; i < 10000; i++)
                    {
                        tasks.Add(Task.Run(() =>
                        {
                            Singleton singleton = Singleton.CreateInstance();
                            singleton.Increment();
                        }));
                    }
                    Task.WaitAll(tasks.ToArray());
                    Singleton.Show();
                    //即使是單例,變數也不是線程安全的,單例不是為了保證線程安全。
                    //iTotal 是0  1   10000  還是其他的
                    //結果為:其他值,1到10000範圍內都可能   線程不安全
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Read();
        }
    }
}

1.2、餓漢式寫法(靜態構造函數)

using System;
using System.Threading;

namespace SingletonPattern
{
    /// <summary>
    /// 餓漢式
    /// </summary>
    public class SingletonSecond
    {
        private static SingletonSecond _singletonSecond = null;

        /// <summary>
        /// 構造函數耗時耗資源
        /// </summary>
        private SingletonSecond()
        {
            long lResult = 0;
            for (int i = 0; i < 10000000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine("{0}被構造一次", this.GetType().Name);
        }

        /// <summary>
        /// 靜態構造函數:由CLR保證,程式第一次使用這個類型前被調用,且只調用一次。
        /// </summary>
        static SingletonSecond()
        {
            _singletonSecond = new SingletonSecond();
            Console.WriteLine("SingletonSecond 被啟動");
        }

        /// <summary>
        /// 餓漢式  只要使用類就會被構造
        /// </summary>
        /// <returns>
        /// </returns>
        public static SingletonSecond CreateInstance()
        {
            return _singletonSecond;
        }
    }
}

1.3、餓漢式寫法(靜態欄位)

using System;
using System.Threading;

namespace SingletonPattern
{
    /// <summary>
    /// 餓漢式
    /// </summary>
    public class SingletonThird
    {
        /// <summary>
        /// 靜態欄位:在第一次使用這個類之前,由CLR保證,初始化且只初始化一次。
        /// 這個比構造函數還早
        /// </summary>
        private static SingletonThird _singletonThird = new SingletonThird(); //列印個日誌

        /// <summary>
        /// 構造函數耗時耗資源
        /// </summary>
        private SingletonThird()
        {
            long lResult = 0;
            for (int i = 0; i < 10000000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine("{0}被構造一次", this.GetType().Name);
        }

        /// <summary>
        /// 餓漢式  只要使用類就會被構造
        /// </summary>
        /// <returns>
        /// </returns>
        public static SingletonThird CreateInstance()
        {
            return _singletonThird;
        }

        public void Show()
        {
            Console.WriteLine("這裡是{0}.Show", this.GetType().Name);
        }
    }
}

2、原型模式(Prototype Pattern)

原型模式:

  換個方式創建對象,不走構造函數,而是記憶體拷貝。

  單例的基礎上升級了一下,把對象從記憶體層面複製了一下,然後返回。

  是個新對象,但是又不是new出來的。

using System;
using System.Threading;

namespace PrototypePattern
{
    /// <summary>
    /// 原型模式:單例的基礎上升級了一下,把對象從記憶體層面複製了一下,然後返回。
    /// 是個新對象,但是又不是new出來的。
    /// </summary>
    public class Prototype
    {
        /// <summary>
        /// 構造函數耗時耗資源
        /// </summary>
        private Prototype()
        {
            long lResult = 0;
            for (int i = 0; i < 10000000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(2000);
            Console.WriteLine("{0}被構造一次", this.GetType().Name);
        }

        /// <summary>
        /// 全局唯一靜態  重用這個變數
        /// </summary>
        private static volatile Prototype _prototype = new Prototype();

        /// <summary>
        /// 公開的靜態方法提供對象實例
        /// </summary>
        /// <returns>
        /// </returns>
        public static Prototype CreateInstance()
        {
            Prototype prototype = (Prototype)_prototype.MemberwiseClone(); //從記憶體層面複製
            return prototype;
        }
    }
}

下麵為了演示鼎鼎大名的三大工廠我們創建幾個介面和類:

/// <summary>
/// 種族
/// </summary>
public interface IRace
{
    void ShowKing();
}

/// <summary>
/// 軍隊
/// </summary>
public interface IArmy
{
    void ShowArmy();
}

/// <summary>
/// 英雄
/// </summary>
public interface IHero
{
    void ShowHero();
}

/// <summary>
/// 資源
/// </summary>
public interface IResource
{
    void ShowResource();
}

/// <summary>
/// 幸運值
/// </summary>
public interface ILuck
{
    void ShowLuck();
}
using System;
using FactoryPattern.War3.Interface;

namespace FactoryPattern.War3.Service
{
    /// <summary>
    /// 人族(War3種族之一)
    /// </summary>
    public class Human : IRace
    {
        public Human(int id, DateTime dateTime, string reamrk)
        { }

        public Human()
        { }

        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Sky");
        }
    }

    public class HumanArmy : IArmy
    {
        public void ShowArmy()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "footman,火槍,騎士,獅鷲");
        }
    }

    public class HumanHero : IHero
    {
        public void ShowHero()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "大法師、山丘、聖騎士、血法師");
        }
    }

    public class HumanResource : IResource
    {
        public void ShowResource()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
        }
    }
}
using System;
using FactoryPattern.War3.Interface;

namespace FactoryPattern.War3.Service
{
    /// <summary>
    /// 不死族(War3種族之一)
    /// </summary>
    public class Undead : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "GoStop");
        }
    }

    public class UndeadArmy : IArmy
    {
        public void ShowArmy()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "食屍鬼,蜘蛛,雕像,戰車,憎惡,冰霜巨龍");
        }
    }

    public class UndeadHero : IHero
    {
        public void ShowHero()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "DK、Lich、小強、恐懼魔王");
        }
    }

    public class UndeadResource : IResource
    {
        public void ShowResource()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
        }
    }
}
using System;
using FactoryPattern.War3.Interface;

namespace FactoryPattern.War3.Service
{
    /// <summary>
    /// War3種族之一
    /// </summary>
    public class ORC : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Grubby");
        }
    }

    public class ORCArmy : IArmy
    {
        public void ShowArmy()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "大G、風騎士、蝙蝠、戰車、牛頭人");
        }
    }

    public class ORCHero : IHero
    {
        public void ShowHero()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "劍聖、小薩滿、先知、牛頭人酋長");
        }
    }

    public class ORCResource : IResource
    {
        public void ShowResource()
        {
            Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
        }
    }
}
using System;
using FactoryPattern.War3.Interface;

namespace FactoryPattern.War3.Service
{
    /// <summary>
    /// War3種族之一
    /// </summary>
    public class NE : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
        }
    }
}

3、簡單工廠(Simple Factory)

簡單工廠:不直接new,把對象創建轉移到工廠類。(簡單工廠不屬於23種設計模式

核心代碼如下:

using System;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;

namespace SimpleFactory
{
    /// <summary>
    /// 簡單工廠
    /// </summary>
    public class ObjectFactory
    {
        /// <summary>
        /// 細節沒有消失  只是轉移
        /// 轉移了矛盾,並沒有消除矛盾
        /// 此處集中了矛盾
        /// </summary>
        /// <param name="raceType">
        /// </param>
        /// <returns>
        /// </returns>
        public static IRace CreateRace(RaceType raceType)
        {
            IRace iRace;
            switch (raceType)
            {
                case RaceType.Human:
                    iRace = new Human();
                    break;
                case RaceType.Undead:
                    iRace = new Undead();
                    break;
                case RaceType.ORC:
                    iRace = new ORC();
                    break;
                case RaceType.NE:
                    iRace = new NE();
                    break;
                //每增加一個分支就需要修改代碼
                default:
                    throw new Exception("wrong raceType");
            }

            return iRace;
        }
    }

    /// <summary>
    /// 種族類型枚舉
    /// </summary>
    public enum RaceType
    {
        Human,
        Undead,
        ORC,
        NE
    }
}
using System;
using FactoryPattern.War3.Interface;

namespace SimpleFactory
{
    /// <summary>
    /// 玩家
    /// </summary>
    public class Player
    {
        public int Id { get; set; }
        public string Name { get; set; }

        /// <summary>
        /// 面向抽象
        /// </summary>
        /// <param name="race">
        /// 種族
        /// </param>
        public void PlayWar3(IRace race)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, race.GetType().Name);
            race.ShowKing();
        }
    }
}
using System;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;

namespace SimpleFactory
{
    /// <summary>
    /// 簡單工廠:非常簡單的工廠
    /// 工廠就是創建對象的地方
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Player player = new Player()
                {
                    Id = 123,
                    Name = "候鳥"
                };

                {
                    Human human = new Human();//1 到處都是細節
                    player.PlayWar3(human);
                }

                {
                    IRace human = new Human();//2 左邊是抽象  右邊是細節
                    player.PlayWar3(human);
                }

                {
                    IRace human = ObjectFactory.CreateRace(RaceType.Human); //3 沒有細節  細節被轉移
                    player.PlayWar3(human);
                }

                {
                    IRace undead = ObjectFactory.CreateRace(RaceType.Undead); //4 沒有細節 細節被轉移
                    player.PlayWar3(undead);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Read();
        }
    }
}

4、工廠方法模式(Factory Method Pattern)

工廠方法模式:

  屏蔽對象的創建,留下了擴展空間。

  把簡單工廠拆分成多個工廠,保證每個工廠的相對穩定。

  多new一次工廠,難免,中間層,屏蔽業務類變化的影響,而且可以留下創建對象的擴展空間。

核心代碼如下:

using FactoryPattern.War3.Interface;

namespace FactoryMethod.Factory
{
    public interface IFactory
    {
        /// <summary>
        /// 創建種族
        /// </summary>
        /// <returns>
        /// </returns>
        IRace CreateRace();
    }
}
using System;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;

namespace FactoryMethod.Factory
{
    public class HumanFactory : IFactory
    {
        public virtual IRace CreateRace()
        {
            return new Human();
        }
    }

    /// <summary>
    /// 後期可以對其擴展
    /// </summary>
    public class HumanFactoryAdvanced : HumanFactory
    {
        public override IRace CreateRace()
        {
            Console.WriteLine("123");
            return new Human();
        }
    }
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;

namespace FactoryMethod.Factory
{
    public class UndeadFactory : IFactory
    {
        public IRace CreateRace()
        {
            return new Undead();
        }
    }
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;

namespace FactoryMethod.Factory
{
    public class ORCFactory : IFactory
    {
        public IRace CreateRace()
        {
            return new ORC();
        }
    }
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;

namespace FactoryMethod.Factory
{
    public class NEFactory : IFactory
    {
        public IRace CreateRace()
        {
            return new NE();
        }
    }
}
using System;
using FactoryMethod.Factory;
using FactoryPattern.War3.Interface;

namespace FactoryMethod
{
    /// <summary>
    /// 工廠方法:把簡單工廠拆分成多個工廠,保證每個工廠的相對穩定。
    /// 但是要多new一次工廠? 難免,中間層,屏蔽業務類變化的影響,而且可以留下創建對象的擴展空間。
    /// 開閉原則:對擴展開發,對修改封閉。
    /// 工廠方法完美遵循了開閉原則
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                {
                    //human
                    IFactory factory = new HumanFactory();//包一層
                    IRace race = factory.CreateRace();
                    //何苦  搞了這麼多工廠 還不是創建個對象
                    //以前依賴的是Human  現在換成了HumanFactory
                    //1 工廠可以增加一些創建邏輯  屏蔽對象實例化的複雜度
                    //2 對象創建的過程中  可能擴展(尤其是ioc)
                }

                {
                    //Undead
                    IFactory factory = new UndeadFactory();
                    IRace race = factory.CreateRace();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Read();
        }
    }
}

可以看出工廠方法模式,就是把簡單工廠拆分成多個工廠,保證每個工廠的相對穩定。多new一次工廠,難免,中間層,屏蔽業務類變化的影響,而且可以留下創建對象的擴展空間。

另外工廠方法完美遵循了開閉原則,例如:Demo中原先我們有4個種族,分別為Human、Undead、ORC和NE,此時如果業務發生變化需要增加一個Five種族,

這時候我們只需要添加一個Five工廠類就好了,不會影響原來的代碼。

using System;
using FactoryPattern.War3.Interface;

namespace FactoryPattern.War3.ServiceExtend
{
    /// <summary>
    /// War3種族之一
    /// </summary>
    public class Five : IRace
    {
        public Five()
            : this(1, "old", 1) //當前類的構造函數
        {

        }

        public Five(int id, string name, int version)
        {

        }

        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
        }
    }
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.ServiceExtend;

namespace FactoryMethod.Factory
{
    /// <summary>
    /// 比如構造很複雜。。比如依賴其他對象
    /// 屏蔽變化
    /// </summary>
    public class FiveFactory : IFactory
    {
        public virtual IRace CreateRace()
        {
            //return new Five();
            return new Five(2, "New", 2);
        }
    }
}

5、抽象工廠模式(Abstract Factory Pattern)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、廣播數據包 1.特性 這種通信類似於廣播,要想實現這個功能,需要使用特殊的IP地址,要想實現多播或者廣播通信的主機必須加入一個D類地址,D類地址的十進位表示範圍為224.0.0.0~239.255.255.255 需要使用的類是`java.net.MulticastSocket. 常用的構建方法 ...
  • Numpy是Python中用於處理數組的一個非常強大的庫,同時也是Pandas等數據處理的庫的核心,如果你有大量處理數組類型數據的操作,比如操作CSV文件數據或涉及數組的科學計算等,那麼Numpy是一個非常好的選擇。 註:此筆記中主要是以一維數組和二維數組作為示例,更高維的數組因為用的較少,同時原理 ...
  • 本文源碼:GitHub·點這裡 || GitEE·點這裡 一、JTA組件簡介 1、JTA基本概念 JTA即Java-Transaction-API,JTA允許應用程式執行分散式事務處理,即在兩個或多個網路電腦資源上訪問並且更新數據。JDBC驅動程式對JTA的支持極大地增強了數據訪問能力。 XA協議 ...
  • 通道 Coroutine\Channel 使用本地記憶體,不同的進程之間記憶體是隔離的。 只能在同一進程的不同協程內進行 push 和 pop 操作。 Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]); Co\run(function(){ // 設置一個容量為1的通道 ...
  • 本文總結了Java集合容器的經典面試題,所有題目我都給出了自己思考,適合面試前複習掃盲使用。我不能保證裡面包含了所有集合面試題,但只要認真深挖好每一道題,做到觸類旁通,就能以不變應萬變。 大綱: 概述型面試題 List Map 小結 概述類面試題 1. 請說一下Java容器集合的分類,各自的繼承結構 ...
  • 介紹 在JDK1.5以後,我們可以使用agent技術構建一個獨立於應用程式的代理程式(即為Agent),用來協助監測、運行甚至替換其他JVM上的程式。使用它可以實現虛擬機級別的AOP功能。Agent分為兩種,一種是在主程式之前運行的Agent,一種是在主程式之後運行的Agent(前者的升級版,1.6 ...
  • 同步和非同步,阻塞和非阻塞是大家經常會聽到的概念,但是它們是從不同維度來描述一件事情,常常很容易混為一談。 ##1. 同步和非同步 同步和非同步描述的是消息通信的機制。 ###同步 當一個request發送出去以後,會得到一個response,這整個過程就是一個同步調用的過程。哪怕response為空,或 ...
  • 在WinForm程式中,實現TextBox文本輸入框占位符的方式也很多,最常用的是方式基於Windows Api SendMessage函數發送EM_SETCUEBANNER消息,或者通過TextBox自帶的焦點事件處理。 ###SendMessage函數實現 創建一個繼承TextBox的ZhmTe ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...