用C# (.NET Core) 實現迭代器設計模式

来源:https://www.cnblogs.com/cgzl/archive/2018/04/20/8891124.html
-Advertisement-
Play Games

本文的概念來自深入淺出設計模式一書 項目需求 有兩個飯店合併了, 它們各自有自己的菜單. 飯店合併之後要保留這兩份菜單. 這兩個菜單是這樣的: 菜單項MenuItem的代碼是這樣的: 最初我們是這樣設計的, 這是第一份菜單: 這是第2份菜單: 同時有兩個菜單存在的問題 問題就是多個菜單把事情變複雜了 ...


本文的概念來自深入淺出設計模式一書

項目需求

有兩個飯店合併了, 它們各自有自己的菜單. 飯店合併之後要保留這兩份菜單.

這兩個菜單是這樣的:

菜單項MenuItem的代碼是這樣的:

最初我們是這樣設計的, 這是第一份菜單:

這是第2份菜單:

同時有兩個菜單存在的問題

問題就是多個菜單把事情變複雜了. 例如: 如果一個服務員需要使用兩份菜單的話, 那麼她就無法很快的告訴客戶有哪些菜是適合素食主義者的了.

服務員還有可能有這些需求:

列印菜單, 列印早餐菜單, 列印午餐菜單, 列印素食菜單, 判斷某個菜是否是素食的.

首先我們嘗試一下如何實現列印菜單:

1. 調用兩個菜單上面的getMenuItem()方法來獲取各自的菜單項, 由於它們的菜單不同, 所以需要寫兩段代碼:

2. 列印兩個菜單的菜單項, 同樣也是兩套代碼:

3. 如果還有一份菜單, 那麼就需要寫三套代碼....

現在就很麻煩了. 

怎麼解決這個問題

 如果能找到一種方式讓這兩個菜單同時實現一個介面就好了. 我們已經知道, 要把變化的部分封裝起來.

什麼是變化的部分? 由於不同對象集合引起的遍歷操作.

那我們試試;

1. 想要遍歷早餐項, 我們使用ArrayList的size()和get()方法:

2. 想要遍歷午餐項, 我們需要使用Array的length成員變數以及通過索引訪問數組:

3. 如果我們創建一個對象, 把它叫做迭代器, 讓它來封裝我們遍歷集合的方式怎麼樣?

這裡, 我們需要早餐菜單創建一個迭代器, 如果還有剩餘的菜單項沒有遍歷完, 就獲取下一個菜單項.

4. 讓我們在Array上試試:

初識迭代器模式

首先你需要知道這種模式依賴於一個迭代器介面. 例如這個:

hasNext()方法告訴我們集合中是否還有剩餘的條目沒有遍歷到.

next()方法返回下一個條目.

有了這個介面, 我們可以在任何一種集合上實現該介面.:

修改代碼

定義迭代器介面:

然後再DinerMenu上實現迭代器介面:

然後使用迭代器來修改DinerMenu菜單:

註意: 不要直接返回集合, 因為這樣會暴露內部實現.

createIterator()方法返回的是迭代器的介面, 客戶並不需要知道DinerMenu是如何維護菜單項的, 也不需要DinerMenu的迭代器是如何實現的. 它只是用迭代器來遍歷菜單裡面的條目.

最後服務員的代碼如下:

測試代碼:

我們做了哪些修改?

我們只是為菜單添加了createIterator()方法.

而現在, 菜單的實現被封裝了, 服務員不知道菜單是如何保存菜單項的.

我們所需要的只是一個迴圈, 它可以多態的處理實現了迭代器介面的集合.

而服務員使用的是迭代器介面.

現在呢, 菜單還沒有共同的介面, 這意味著服務員仍然被綁定在兩個具體的菜單類上, 一會我們再說這個.

當前的設計圖

目前就是兩個菜單實現了同一套方法, 但是還沒有實現同一個介面.

使用C#, .NET Core控制台項目進行實現

菜單項 MenuItem:

namespace IteratorPattern.Menus
{
    public class MenuItem
    {
        public string Name { get; }
        public string Description { get; }
        public bool Vegetarian { get; }
        public double Price { get; }

        public MenuItem(string name, string description, bool vegetarian, double price)
        {
            Name = name;
            Description = description;
            Vegetarian = vegetarian;
            Price = price;
        }
    }
}

迭代器介面 IMyIterator:

namespace IteratorPattern.Abstractions
{
    public interface IMyIterator
    {
        bool HasNext();
        object Next();
    }
}

兩個菜單迭代器:

using IteratorPattern.Abstractions;
using IteratorPattern.Menus;

namespace IteratorPattern.MenuIterators
{
    public class MyDinerMenuIterator: IMyIterator
    {
        private readonly MenuItem[] _menuItems;
        private int _position;

        public MyDinerMenuIterator(MenuItem[] menuItems)
        {
            _menuItems = menuItems;
        }

        public bool HasNext()
        {
            if (_position >= _menuItems.Length || _menuItems[_position] == null)
            {
                return false;
            }
            return true;
        }

        public object Next()
        {
            var menuItem = _menuItems[_position];
            _position++;
            return menuItem;
        }
    }
}

using System.Collections;
using IteratorPattern.Abstractions;

namespace IteratorPattern.MenuIterators
{
    public class MyPancakeHouseMenuIterator:IMyIterator
    {
        private readonly ArrayList _menuItems;
        private int _position;

        public MyPancakeHouseMenuIterator(ArrayList menuItems)
        {
            _menuItems = menuItems;
        }

        public bool HasNext()
        {
            if (_position >= _menuItems.Count || _menuItems[_position] == null)
            {
                return false;
            }
            _position++;
            return true;
        }

        public object Next()
        {
            var menuItem = _menuItems[_position];
            _position++;
            return menuItem;
        }
    }
}

兩個菜單:

using System;
using System.Collections.Generic;
using System.Text;
using IteratorPattern.Abstractions;
using IteratorPattern.MenuIterators;

namespace IteratorPattern.Menus
{
    public class MyDinerMenu
    {
        private const int MaxItems = 6;
        private int _numberOfItems = 0;
        private MenuItem[] MenuItems { get; }

        public MyDinerMenu()
        {
            MenuItems = new MenuItem[MaxItems];
            AddItem("Vegetarian BLT", "(Fakin’) Bacon with lettuce & tomato on whole wheat", true, 2.99);
            AddItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);
            AddItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);
            AddItem("Hotdog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05);
        }

        public void AddItem(string name, string description, bool vegetarian, double price)
        {
            var menuItem = new MenuItem(name, description, vegetarian, price);
            if (_numberOfItems >= MaxItems)
            {
                Console.WriteLine("Sorry, menu is full! Can't add item to menu");
            }
            else
            {
                MenuItems[_numberOfItems] = menuItem;
                _numberOfItems++;
            }
        }

        public IMyIterator CreateIterator()
        {
            return new MyDinerMenuIterator(MenuItems);
        }
    }
}

using System.Collections;
using IteratorPattern.Abstractions;
using IteratorPattern.MenuIterators;

namespace IteratorPattern.Menus
{
    public class MyPancakeHouseMenu
    {
        public ArrayList MenuItems { get; }

        public MyPancakeHouseMenu()
        {
            MenuItems = new ArrayList();
            AddItem("K&B’s Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99);
            AddItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);
            AddItem("Blueberry Pancakes", "Pancakes made with fresh blueberries", true, 3.49);
            AddItem("Waffles", "Waffles, with your choice of blueberries or strawberries", true, 3.59);
        }

        public void AddItem(string name, string description, bool vegetarian, double price)
        {
            var menuItem = new MenuItem(name, description, vegetarian, price);
            MenuItems.Add(menuItem);
        }

        public IMyIterator CreateIterator()
        {
            return new MyPancakeHouseMenuIterator(MenuItems);
        }
    }
}

服務員 Waitress:

using System;
using IteratorPattern.Abstractions;
using IteratorPattern.Menus;

namespace IteratorPattern.Waitresses
{
    public class MyWaitress
    {
        private readonly MyPancakeHouseMenu _pancakeHouseMenu;
        private readonly MyDinerMenu _dinerMenu;

        public MyWaitress(MyPancakeHouseMenu pancakeHouseMenu, MyDinerMenu dinerMenu)
        {
            _pancakeHouseMenu = pancakeHouseMenu;
            _dinerMenu = dinerMenu;
        }

        public void PrintMenu()
        {
            var pancakeIterator = _pancakeHouseMenu.CreateIterator();
            var dinerIterator = _dinerMenu.CreateIterator();
            Console.WriteLine("MENU\n--------------\nBREAKFIRST");
            PrintMenu(pancakeIterator);
            Console.WriteLine("\nLUNCH");
            PrintMenu(dinerIterator);
        }

        private void PrintMenu(IMyIterator iterator)
        {
            while (iterator.HasNext())
            {
                var menuItem = iterator.Next() as MenuItem;
                Console.Write($"{menuItem?.Name}, ");
                Console.Write($"{menuItem?.Price} -- ");
                Console.WriteLine($"{menuItem?.Description}");
            }
        }
    }
}

測試:

        static void MenuTestDriveUsingMyIterator()
        {
            var pancakeHouseMenu = new MyPancakeHouseMenu();
            var dinerMenu = new MyDinerMenu();

            var waitress = new MyWaitress(pancakeHouseMenu, dinerMenu);
            waitress.PrintMenu();
        }

做一些改進

 Java裡面內置了Iterator介面, 我們剛纔是手寫了一個Iterator迭代器介面. Java內置的定義如下:

註意裡面這個remove()方法, 我們可能不需要它.

remove()方法是可選實現的, 如果你不想讓集合有此功能的話, 就應該拋出NotSupportedException(C#的).

使用java內置的Iterator來實現

由於PancakeHouseMenu使用的是ArrayList, 而ArrayList已經實現了該介面, 那麼:這樣簡單改一下就可以:

針對DinerMe菜單, 還是需要手動實現的:

最後別忘了給菜單規定一個統一的介面:

服務員Waitress類裡面也使用Menu來代替具體的菜單, 這樣也減少了服務員對具體類的依賴(針對介面編程, 而不是具體的實現):

最後看下改進後的設計類圖:

迭代器模式定義

迭代器模式提供了一種訪問聚合對象(例如集合)元素的方式, 而且又不暴露該對象的內部表示.

迭代器模式負責遍歷該對象的元素, 該項工作由迭代器負責而不是由聚合對象(集合)負責.

類圖:

其它問題

  • 迭代器分內部迭代器和外部迭代器, 我們上面實現的是外部迭代器. 也就是說客戶控制著迭代, 它通過調用next()方法來獲取下個元素. 而內部迭代器由迭代器本身自己控制迭代, 這種情況下, 你需要告訴迭代器遍歷的時候需要做哪些動作, 所以你得找到一種方式把操作傳遞進去. 內部迭代器還是不如外部的靈活, 但是也許使用起來會簡單一些?
  • 迭代器意味著無序. 它所遍歷的集合的順序是根據集合來定的, 也有可能會遍歷出來的元素值會重覆.

單一職責設計原則

一個類應該只有一個變化發生的原因.

寫代碼的時候這個原則很容易被忽略掉, 只能通過多檢查設計來避免違反原則.

所謂的高內聚, 就是只這個類是圍繞一套關連的函數而設計的.

而低內聚就是只這個類是圍繞一些不相關的函數而設計的.

遵循該原則的類通常是高內聚的, 並且可維護性要比那些多重職責或低內聚的類好.

需求變更

還需要添加另一份菜單:

這個菜單使用的是HashTable.

首先修改該菜單, 讓它實現Menu介面:

註意看HashTable的不同之處:

首先通過values()方法獲取HashTable的集合對象, 這個對象正好實現了Iterator介面, 直接調用iterator()方法即可.

最後修改服務員類:

測試:

 到目前我們做了什麼

 我們給了服務員一種簡單的方式來遍歷菜單項, 不同的菜單實現了同一個迭代器介面, 服務員不需要知道菜單項的實現方法.

 我們把服務員和菜單的實現解耦了

 

而且使服務員可以擴展:

還有個問題

現在有三個菜單, 每次再添加一個菜單的時候, 你都得相應的添加一套代碼, 這違反了"對修改關閉, 對擴展開放原則".

那我們把這些菜單放到可迭代的集合即可:

C#, .NET Core控制帶項目實現

菜單介面:

using System.Collections;

namespace IteratorPattern.Abstractions
{
    public interface IMenu
    {
        IEnumerator CreateIEnumerator();
    }
}

 

三個菜單:

using System;
using System.Collections;
using IteratorPattern.Abstractions;
using IteratorPattern.MenuIterators;

namespace IteratorPattern.Menus
{
    public class DinerMenu: IMenu
    {
        private const int MaxItems = 6;
        private int _numberOfItems = 0;
        private MenuItem[] MenuItems { get; }

        public DinerMenu()
        {
            MenuItems = new MenuItem[MaxItems];
            AddItem("Vegetarian BLT", "(Fakin’) Bacon with lettuce & tomato on whole wheat", true, 2.99);
            AddItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);
            AddItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);
            AddItem("Hotdog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05);
        }

        public void AddItem(string name, string description, bool vegetarian, double price)
        {
            var menuItem = new MenuItem(name, description, vegetarian, price);
            if (_numberOfItems >= MaxItems)
            {
                Console.WriteLine("Sorry, menu is full! Can't add item to menu");
            }
            else
            {
                MenuItems[_numberOfItems] = menuItem;
                _numberOfItems++;
            }
        }

        public IEnumerator CreateIEnumerator()
        {
            return new DinerMenuIterator(MenuItems);
        }
    }
}

using System.Collections;
using IteratorPattern.Abstractions;
using IteratorPattern.MenuIterators;

namespace IteratorPattern.Menus
{
    public class PancakeHouseMenu: IMenu
    {
        public ArrayList MenuItems { get; }

        public PancakeHouseMenu()
        {
            MenuItems = new ArrayList();
            AddItem("K&B’s Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99);
            AddItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);
            AddItem("Blueberry Pancakes", "Pancakes made with fresh blueberries", true, 3.49);
            AddItem("Waffles", "Waffles, with your choice of blueberries or strawberries", true, 3.59);
        }

        public void AddItem(string name, string description, bool vegetarian, double price)
        {
            var menuItem = new MenuItem(name, description, vegetarian, price);
            MenuItems.Add(menuItem);
        }

        public IEnumerator CreateIEnumerator()
        {
            return new PancakeHouseMenuIterator(MenuItems);
        }
    }
}

using System.Collections;
using IteratorPattern.Abstractions;

namespace IteratorPattern.Menus
{
    public class CafeMenu : IMenu
    {
        public Hashtable MenuItems { get; } = new Hashtable();

        public CafeMenu()
        {
            AddItem("Veggie Burger and Air Fries", "Veggie burger on a whole wheat bun, lettuce, tomato, and fries", true, 3.99);
            AddItem("Soup of the day", "A cup of the soup of the day, with a side salad", false, 3.69);
            AddItem("Burrito", "A large burrito, with whole pinto beans, salsa, guacamole", true, 4.29);
        }

        public IEnumerator CreateIEnumerator()
        {
            return MenuItems.GetEnumerator();
        }

        public void AddItem(string name, string description, bool vegetarian, double price)
        {
            var menuItem = new MenuItem(name, description, vegetarian, price);
            MenuItems.Add(menuItem.Name, menuItem);
        }

    }
}

菜單的迭代器:

using System;
using System.Collections;
using IteratorPattern.Menus;

namespace IteratorPattern.MenuIterators
{
    public class DinerMenuIterator: IEnumerator
    {
        private readonly MenuItem[] _menuItems;
        private int _position = -1;

        public DinerMenuIterator(MenuItem[] menuItems)
        {
            _menuItems = menuItems;
        }

        public bool MoveNext()
        {
            _position++;
            if (_position >= _menuItems.Length || _menuItems[_position] == null)
            {
                return false;
            }
            return true;
        }

        public void Reset()
        {
            _position = -1;
        }

        public object Current => _menuItems[_position];
    }
}
using System.Collections;
using System.Collections.Generic;

namespace IteratorPattern.MenuIterators
{
    public class PancakeHouseMenuIterator : IEnumerator
    {
        private readonly ArrayList _menuItems;
        private int _position = -1;

        public PancakeHouseMenuIterator(ArrayList menuItems)
        {
            _menuItems = menuItems;
        }

        public bool MoveNext()
        {
            _position++;
            if (_position >= _menuItems.Count || _menuItems[_position] == null)
            {
                return false;
            }
            return true;
        }

        public void Reset()
        {
            _position = -1;
        }

        public object Current => _menuItems[_position];
    }
}

服務員:

using System;
using System.Collections;
using IteratorPattern.Abstractions;
using IteratorPattern.Menus;

namespace IteratorPattern.Waitresses
{
    public class Waitress
    {
        private readonly ArrayList _menus;

        public Waitress(ArrayList menus)
        {
            _menus = menus;
        }

        public void PrintMenu()
        {
            var menuIterator = _menus.GetEnumerator();
            while (menuIterator.MoveNext())
            {
                var menu = menuIterator.Current as IMenu;
                PrintMenu(menu?.CreateIEnumerator());
            }
        }

        private void PrintMenu(IEnumerator iterator)
        {
            while (iterator.MoveNext())
            {
                if (iterator.Current != null)
                {
                    MenuItem menuItem;
                    if (iterator.Current is MenuItem item)
                    {
                        menuItem = item;
                    }
                    else
                    {
                        menuItem = ((DictionaryEntry)iterator.Current).Value as MenuItem;
                    }
                    Console.Write($"{menuItem?.Name}, ");
                    Console.Write($"{menuItem?.Price} -- ");
                    Console.WriteLine($"{menuItem?.Description}");
                }
            }
            Console.WriteLine();
        }
    }
}

測試:

        static void MenuTestDriveUsingIEnumerator()
        {
            var pancakeHouseMenu = new PancakeHouseMenu();
            var dinerMenu = new DinerMenu();
            var cafeMenu = new CafeMenu();

            var waitress = new Waitress(new ArrayList(3)
            {
                pancakeHouseMenu, dinerMenu, cafeMenu
            });
            waitress.PrintMenu();
        }

 

 

深入淺出設計模式的C#實現的代碼: https://github.com/solenovex/Head-First-Design-Patterns-in-CSharp

這篇先到這, 本章涉及到組合模式, 下篇文章再寫.

 


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

-Advertisement-
Play Games
更多相關文章
  • PHP配置 引用mysqli擴展 不需要絕對路徑 如果不啟用,那麼引用mysqli擴展必須使用絕對路徑引用 建立和斷開鏈接 獲取錯誤信息 獲取錯誤碼 獲取錯誤信息 在單獨的文件中存儲鏈接信息 在必要時包含此文件 與資料庫交互 向資料庫發送查詢 ·獲取數據 query()方法 mysqli_store ...
  • 1.創建一個SpringBoot項目,參考:http://www.cnblogs.com/i-tao/p/8878562.html 2.創建項目目錄結構 3.整合Mybatis 3.1、在pom.xml文件里添加mysql連接驅動和mybatis依賴 3.2、application.properti ...
  • 樹 樹型結構是一類重要的非線性數據結構。樹是n(n>=0)個結點的有限集。在任意一顆非空樹中,有且僅有 一個特定的稱為根的結點;當n>1時,其餘結點可分為m(m>0)個互不相交的有限集T1,T2,...,Tm,其中每一個 集合本身又是一棵樹,並且稱為根的子樹。因此樹的數據結構定義為: 在樹型結構中可 ...
  • 在前兩個文章中整理了關於BaseServer部分以及BaseRequestHandler,以及通過對TCP的處理的流程的整理,這次整理的是剩下的關於用於擴展的部分,這裡通過對線程擴展進行整理 ThreadingMixIn ThreadingMixIn 類實現了多線程的方式,它只有兩個方法,分別是pr ...
  • 本章採取問答式,說一說.net Core里生命周期的常見問題。【譯】 1.什麼是. NET Core?. NET Core是一組運行時、庫和編譯器組件, 可用於設備和雲工作負載的各種配置。跨平臺和開源,. NET Core提供了一個輕量開發模型可以靈活的工作在各種開發工具 OS 平臺。. NET C ...
  • 初學C#,整天對著業務邏輯,寫反反覆復的“過程型”代碼邏輯十分枯燥,不如用點新東西提升一下代碼效率,讓代碼看起來更有逼格?! 好,下麵我們看看C#中簡單易學的泛型。 首先,我寫了一個這樣的方法 Say(string spk),併在主函數中進行調用: 如果,我說:123,則需要另一個方法 Say(in ...
  • 上一篇,我們介紹瞭如何讀取自定義的json文件,數據是讀取出來了,只是處理的時候太麻煩,需要一遍一遍寫,很枯燥.那麼有沒有很好的辦法呢?經過鑽研,辦法有了. 既然一個一個讀取比較麻煩,那麼可以把它放入一個類裡面麽?當然可以.這樣直接註入這個類,讓控制器去讀取,那麼就不需要每次載入它了,一次載入就可以 ...
  • 查了下 轉PDF的各種框架 發現大部分都是收費的。 發現一款免費的iTextSharp 就想玩一下 只是簡單做個HTML 轉PDF 沒有過深的探究。 首先 我在項目中引入iTextSharp 還是老方法 要麼 NuGet上下載 或者 直接命令 然後在項目中建了一個HTML 裡面就是一些簡單的標簽 和 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...