設計模式——行為型設計模式

来源:https://www.cnblogs.com/buchizicai/archive/2022/08/17/16580773.html
-Advertisement-
Play Games

行為型模式(Behavioral Pattern)是指對在不同對象之間劃分責任和演算法進行抽象化的設計模式,它不僅關註類和對象的結構,而且重點關註他們之間的相互作用。 對於一個系統來說,對象不是孤立運行的,對象之間可以通過相互通信和協作完成某些複雜的功能,對象之間是相互影響的。 ...


行為型設計模式

針對對象之間的交互

解釋器模式

java中用的很。JVM編譯的時候就是對我們寫的代碼進行瞭解釋操作;資料庫SQL語句亦是如此

解釋器:對語言進行解釋,根據不同語義來做不同的事情。

舉例:雙棧計算器

public class 雙棧實現計算器 {
    //設置兩棧
    private static Deque<Character> opr = new LinkedList<>();
    private static Deque<Double> number = new LinkedList<>();

    public static void main(String[] args) {
        //接收一串字元串並轉字元數組
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        char [] arrC = str.toCharArray();

        for (int i = 0; i < arrC.length;) {
            char c = arrC[i];
            //是+-/*字元時
            if (isChar(c)){
                ///如果棧內有字元,則需要判斷優先順序,入棧字元小於等於棧內字元則需要先計算棧內字元
                Character peek = opr.peek();    //細節!!! 這裡必須先取
                while (peek!=null && isLowIn(c,peek)){
                    cal();
                    peek=opr.peek();       //細節!!這裡也必須更新peek
                }
                //入棧
                opr.push(c);
                i++;
            }
            //字元是數字時
            else {
                double sum=0;   //接收整數和
                double sum2=0;  //接收小數和
                int times = 1;  //記錄當前小數位數
                boolean flag=false; //是否開啟小數檢測模式

                //判斷下一個是不是+-*/,不是的話就繼續判斷直到非數字
                while (i<=arrC.length-1 && !isChar(arrC[i])){       //細節:括弧內兩者順序不能改變
                    //遇到小數的情況
                    if (arrC[i]=='.'){
                        flag=true;
                    }else {
                        //小數情況
                        if (flag){
                            double val=arrC[i]-'0';
                            for (int j = 0; j < times; j++) {   //細節!用times縮小值
                                val/=10.0;
                            }
                            times++;
                            sum2+=val;
                        }
                        //正數情況
                        else {
                            sum=sum*10+arrC[i]-'0';     //獲取多位數字的關鍵!!!
                        }
                    }
                    i++;
                }
                number.push(sum+sum2);
            }
        }
        //字元都獲取完了後棧內還有數字和字元的話,就計算完棧內的數據並輸出最終結果
        while (!opr.isEmpty()) cal();
        System.out.println(number.peek());
    }

    //判斷是否為字元
    public static boolean isChar(char c) {
        return c=='+'||c=='-'||c=='*'||c=='/';
    }

    //判斷優先順序是否是棧外字元小於等於棧內字元
    public static boolean isLowIn(char out,char in){
        return (out=='+'||out=='-')||(in=='*'||in=='/');
    }

    public static void cal(){
        //從棧內取出兩個數組和一個字元
        double a = number.pop();
        double b = number.pop();
        char c = opr.poll();

        //根據字元c進行不同的運算
        switch (c){
            case '+':
                number.push(a+b);
                break;
            case '-':
                number.push(b-a);
                break;
            case '*':
                number.push(b*a);
                break;
            case '/':
                number.push(b/a);
                break;
            default:
                System.out.println("字元輸入有誤");
        }
    }

}

模板方法模式

在執行一類業務時前面有很多步驟都是相同時,就可以寫一個模板抽象類,留出一個方法去給子類定義業務最後的操作。

該模式在源碼中大量的被應用。這樣寫會給後期維護提供非常清晰的思路

舉例:去醫院看病,掛號和看醫生是固定模式,但後面要不要開處方藥和拿藥是不一定的

//模板抽象類
/**
 * 抽象診斷方法,因為現在只知道掛號和看醫生是固定模式,剩下的開處方和拿藥都是不確定的
 */
public abstract class AbstractDiagnosis {

    public void test(){
        System.out.println("今天頭好暈,不想起床,開擺,先跟公司請個假");
        System.out.println("去醫院看病了~");
        System.out.println("1 >> 先掛號");
        System.out.println("2 >> 等待叫號");
        //由於現在不知道該開什麼處方,所以只能先定義一下行為,然後具體由子類實現
      	//大致的流程先定義好就行
        this.prescribe();
        this.medicine();  //開藥同理
    }

    public abstract void prescribe();   //開處方操作根據具體病癥決定了

    public abstract void medicine();   //拿藥也是根據具體的處方去拿
}

//實現具體業務的子類
/**
 * 感冒相關的具體實現子類
 */
public class ColdDiagnosis extends AbstractDiagnosis{
    @Override
    public void prescribe() {
        System.out.println("3 >> 一眼丁真,鑒定為假,你這不是感冒,純粹是想擺爛");
    }

    @Override
    public void medicine() {
        System.out.println("4 >> 開點頭孢回去吃吧");
    }
}

//主方法
public static void main(String[] args) {
    AbstractDiagnosis diagnosis = new ColdDiagnosis();
    diagnosis.test();
}

責任鏈模式

就像闖關,一層接一層的往下進行。可以理解為報銷的時候需要一層一層審批

比如JavaWeb中學習的Filter過濾器,正是採用的責任鏈模式,通過將請求一級一級不斷向下傳遞,來對我們所需要的請求進行過濾和處理。

image

舉例:這裡就使用責任鏈模式來模擬一個簡單的面試過程,面試也是一面二面三面這樣走的流程,這裡先設計一下責任鏈上的各個處理器

//設計模板抽象方法,併在此基礎上寫層層往下的責任鏈
public abstract class Handler {

    protected Handler successor;    //這裡我們就設計責任鏈以單鏈表形式存在,這裡存放後繼節點

    public Handler connect(Handler successor){     //拼接後續節點
        this.successor = successor;
        return successor;  //這裡返回後繼節點,方便我們一會鏈式調用
    }

    public void handle(){
        this.doHandle();   //由不同的子類實現具體處理過程
        Optional
                .ofNullable(successor)	//設置可以為null
                .ifPresent(Handler::handle);    //責任鏈上如果還有後繼節點,就繼續向下傳遞
    }

    public abstract void doHandle();   //結合上節課學習的模板方法,交給子類實現
}

//一面子類
public class FirstHandler extends Handler{   //用於一面的處理器
    @Override
    public void doHandle() {
        System.out.println("============= 白馬程式員一面 ==========");
        System.out.println("1. 談談你對static關鍵字的理解?");
        System.out.println("2. 內部類可以調用外部的數據嗎?如果是靜態的呢?");
        System.out.println("3. hashCode()方法是所有的類都有嗎?預設返回的是什麼呢?");
        System.out.println("以上問題會的,可以依次打在評論區");
    }
}

//二面子類
public class SecondHandler extends Handler{  //二面
    @Override
    public void doHandle() {
        System.out.println("============= 白馬程式員二面 ==========");
        System.out.println("1. 如果我們自己創建一個java.lang包並且編寫一個String類,能否實現覆蓋JDK預設的?");
        System.out.println("2. HashMap的負載因數有什麼作用?變化規律是什麼?");
        System.out.println("3. 線程池的運作機制是什麼?");
        System.out.println("4. ReentrantLock公平鎖和非公平鎖的區別是什麼?");
        System.out.println("以上問題會的,可以依次打在評論區");
    }
}

//三面子類
public class ThirdHandler extends Handler{
    @Override
    public void doHandle() {
        System.out.println("============= 白馬程式員三面 ==========");
        System.out.println("1. synchronized關鍵字瞭解嗎?如何使用?底層是如何實現的?");
        System.out.println("2. IO和NIO的區別在哪裡?NIO三大核心組件?");
        System.out.println("3. TCP握手和揮手流程?少一次握手可以嗎?為什麼?");
        System.out.println("4. 操作系統中PCB是做什麼的?運行機制是什麼?");
        System.out.println("以上問題會的,可以依次打在評論區");
    }
}

//主方法
public static void main(String[] args) {
    Handler handler = new FirstHandler();  //一面首當其衝
    handler
            .connect(new SecondHandler())   //繼續連接二面和三面
            .connect(new ThirdHandler());
    handler.handle();   //開始面試
} 

命令模式

命令模式,此時會有三個頂層行為:遙控器、命令、接收器。

話不多說,直接搬例。小米傢具就是典型的命令模式。只需要在手機(遙控器)上通過紅外線、藍牙等按下一些命令,家中的傢具(接收器)就會執行命令。

舉例:設置三個頂層的 介面/抽象類 ,遙控器、命令、接收器

//遙控器
public class Controller {   //遙控器只需要把我們的指令發出去就行了
    public static void call(Command command){
        command.execute();
    }
}

//命令
public abstract class Command {   //指令抽象,不同的電器有指令

    private final Receiver receiver;

    protected Command(Receiver receiver){   //指定此命令對應的電器(接受者)
        this.receiver = receiver;
    }

    public void execute() {
        receiver.action();   //執行命令,實際上就是讓接收者開始幹活
    }
}

//接收器
public interface Receiver {
    void action();   //具體行為,這裡就寫一個算了
}

//具體接收器
public class AirConditioner implements Receiver{
    @Override
    public void action() {
        System.out.println("空調已開啟,呼呼呼");
    }
}

//具體命令
public class OpenCommand extends Command {
    public OpenCommand(AirConditioner airConditioner) {
        super(airConditioner);
    }
}

//可以創建具體控制器(手機),也可以不創建直接遙控,因為控制器一般只有一個。所以這裡就不創建了

//主方法
public static void main(String[] args) {
    AirConditioner airConditioner = new AirConditioner();   //先創建一個空調
    Controller.call(new OpenCommand(airConditioner));   //直接通過遙控器來發送空調開啟命令
}

迭代器模式

每個集合類都有相應的迭代器。很少自定義,大都是用jdk定義好的迭代器

迭代器最直接的例子就是foreach語法糖。

public static void main(String[] args) {
    List<String> list = Arrays.asList("AAA", "BBB", "CCC");
    for (String s : list) {   //使用foreach語法糖進行迭代,依次獲取每一個元素
        System.out.println(s);   //列印一下
    }
}

上述代碼編譯後的樣子:

public static void main(String[] args) {
    List<String> list = Arrays.asList("AAA", "BBB", "CCC");
    Iterator var2 = list.iterator();   //實際上這裡本質是通過List生成的迭代器來遍歷我們每個元素的

    while(var2.hasNext()) {   //判斷是否還有元素可以迭代,沒有就false
        String s = (String)var2.next();   //通過next方法得到下一個元素,每調用一次,迭代器會向後移動一位
        System.out.println(s);    //列印一下
    }
}

由此可知迭代器原理:使用迭代器對List進行遍歷時,實際上就像一個指向列表頭部的指針,我們通過不斷向後移動指針來依次獲取所指向的元素:

image

image

拓展:自定義迭代器。

(由於每個迭代器需要根據不同的集合類特點來設計,所以自定義迭代器前需要自定義一個集合類)

//自定義集合類
public class ArrayCollection<T> {    //首先設計一個簡單的數組集合,一會我們就迭代此集合內的元素

    private final T[] array;   //底層使用一個數組來存放數據

    private ArrayCollection(T[] array){   //private掉,自己用
        this.array = array;
    }

    public static <T> ArrayCollection<T> of(T[] array){   //開個靜態方法直接吧數組轉換成ArrayCollection,其實和直接new一樣,但是這樣寫好看一點
        return new ArrayCollection<>(array);
    }
}

//自定義迭代器
public class ArrayCollection<T> implements Iterable<T>{   //實現Iterable介面表示此類是支持迭代的

    ...

    @Override
    public Iterator<T> iterator() {    //需要實現iterator方法,此方法會返回一個迭代器,用於迭代我們集合中的元素
        return new ArrayIterator();
    }

    public class ArrayIterator implements Iterator<T> {   //這裡實現一個,註意別用靜態,需要使用對象中存放的數組
        private int cur = 0;   //這裡我們通過一個指針表示當前的迭代位置

        @Override
        public boolean hasNext() {     //判斷是否還有下一個元素
            return cur < array.length;   //如果指針大於或等於數組最大長度,就不能再繼續了
        }

        @Override
        public T next() {   //返回當前指針位置的元素並向後移動一位
            return array[cur++];   //正常返回對應位置的元素,並將指針自增
        }
    }
}

//主方法
public static void main(String[] args) {
    String[] arr = new String[]{"AAA", "BBB", "CCC", "DDD"};
    ArrayCollection<String> collection = ArrayCollection.of(arr);
    for (String s : collection) {    //可以直接使用foreach語法糖,當然最後還是會變成迭代器調用
        System.out.println(s);
    }
}

//編譯主方法後的樣子
public static void main(String[] args) {
    String[] arr = new String[]{"AAA", "BBB", "CCC", "DDD"};
    ArrayCollection<String> collection = ArrayCollection.of(arr);
    Iterator var3 = collection.iterator();   //首先獲取迭代器,實際上就是調用我們實現的iterator方法

    while(var3.hasNext()) {
        String s = (String)var3.next();   //直接使用next()方法不斷向下獲取
        System.out.println(s);
    }
}

中介者模式

將多對多的複雜關係,變成一對多的簡單明瞭關係

話不多說,直接上例子。中介,第一個想到的就是房子的中介。當一堆人需要出租房屋、另一堆人又需要租房,如果沒有中介,那再好的房子很難遇上租客也租不出去,此時就需要一個中介將雙方的需要進行匹配從而實現房子出租的目的。

不找中介:很亂,還不一定能夠遇上需求相同的對方

image

找中介:中介將雙方整理好,進行需求匹配

image

舉例:中介、出租者、租房者

//中介
public class Mediator {   //房產中介
    private final Map<String, User> userMap = new HashMap<>();   //在出售的房子需要存儲一下

    public void register(String address, User user){   //出售房屋的人,需要告訴中介他的房屋在哪裡
        userMap.put(address, user);
    }

    public User find(String address){   //通過此方法來看看有沒有對應的房源
        return userMap.get(address);
    }
}

//出租者和租房者(這裡偷懶就寫在一起了)
public class User {   //用戶可以是出售房屋的一方,也可以是尋找房屋的一方
    String name;
    String tel;

    public User(String name, String tel) {
        this.name = name;
        this.tel = tel;
    }
  
    public User find(String address, Mediator mediator){   //找房子的話,需要一個中介和你具體想找的地方
        return mediator.find(address);
    }

    @Override
    public String toString() {
        return name+" (電話:"+tel+")";
    }
}

//主方法
public static void main(String[] args) {
    User user0 = new User("劉女士", "10086");   //出租者
    User user1 = new User("李先生", "10010");   //租房者
    Mediator mediator = new Mediator();   //我是中介

    mediator.register("廣州市天河區白馬程式員", user0);   //出租人先把房子給中介掛上去

    User user = user1.find("廣州市天河區非馬程式員", mediator);  //租房者向指定中介找房子
    if(user == null) System.out.println("沒有找到對應的房源");
    System.out.println(user);   //成功找到對應房源
}

備忘錄模式

我也稱其為時光回溯模式。比較少用,大都是底層代碼才用

這個備忘錄不是我們平時用於記錄容易忘記的ddl,而是保存曾經某個時刻的狀態,後面有需要就恢復到該時刻的狀態

舉例:保存對象的狀態

//對象實體
public class Student {
    private String currentWork;   //當前正在做的事情
    private int percentage;   //當前的工作完成百分比

    public void work(String currentWork) {
        this.currentWork = currentWork;
        this.percentage = new Random().nextInt(100);
    }

    @Override
    public String toString() {
        return "我現在正在做:"+currentWork+" (進度:"+percentage+"%)";
    }
    
    public State save(){
        return new State(currentWork, percentage);
    }

    public void restore(State state){
        this.currentWork = state.currentWork;
        this.percentage = state.percentage;
    }
}

//狀態保存類
public class State {
    final String currentWork;
    final int percentage;

    State(String currentWork, int percentage) {   //僅開放給同一個包下的Student類使用
        this.currentWork = currentWork;
        this.percentage = percentage;
    }
}

//主方法
public static void main(String[] args) {
    Student student = new Student();
    student.work("學Java");   //開始學Java
    System.out.println(student);

    State savedState = student.save();   //保存一下當前的狀態

    student.work("打電動");   //剛打開B站播放視頻,學一半開始擺爛了
    System.out.println(student);

    student.restore(savedState);   //後悔浪費時間,回到上一個保存的狀態
    System.out.println(student);   //回到學Java的狀態
}

觀察者模式

觀察者模式可以實現監聽器機制,當對象發生改變時,觀察者能夠立即察覺到併進行一些聯動操作。很少用,大都是直接用監聽器

舉例:自定義觀察者

//觀察者介面
public interface Observer {   //觀察者介面
    void update();   //當對象有更新時,會回調此方法
}

//支持觀察者的實體
public class Subject {
    private final Set<Observer> observerSet = new HashSet<>();

    public void observe(Observer observer) {   //添加觀察者
        observerSet.add(observer);
    }

    public void modify() {   //模擬對象進行修改
        observerSet.forEach(Observer::update);   //當對象發生修改時,會通知所有的觀察者,併進行方法回調
    }
}

//主方法
public static void main(String[] args) {
    Subject subject = new Subject();
    subject.observe(() -> System.out.println("我是一號觀察者!"));
    subject.observe(() -> System.out.println("我是二號觀察者!"));
    subject.modify();
}

JDK也提供了是實現觀察者模式的相關介面:

//繼承介面表示支持觀察者
import java.util.Observable;    //java.util包下提供的觀察者抽象類

public class Subject extends Observable {   //繼承此抽象類表示支持觀察者

    public void modify(){
        System.out.println("對對象進行修改!");
        this.setChanged();    //當對對象修改後,需要setChanged來設定為已修改狀態
        this.notifyObservers(new Date());   //使用notifyObservers方法來通知所有的觀察者
      	//註意只有已修改狀態下通知觀察者才會有效,並且可以給觀察者傳遞參數,這裡傳遞了一個時間對象
    }
}

//主方法
public static void main(String[] args) {
    Subject subject = new Subject();
    subject.addObserver((o, arg) -> System.out.println("監聽到變化,並得到參數:"+arg));  
  	//註意這裡的Observer是java.util包下提供的
    subject.modify();   //進行修改操作
}

狀態模式

根據不同的狀態執行不同的行為

水在不同的溫度狀態會隨之改變,程式也可以達到某種狀態後就執行不同的行為

//枚舉狀態
public enum State {   //狀態直接使用枚舉定義
    NORMAL, LAZY
}

//實體類
public class Student {

    private State state;   //使用一個成員來存儲狀態

    public void setState(State state) {
        this.state = state;
    }

    public void study(){  
        switch (state) {   //根據不同的狀態,學習方法會有不同的結果
            case LAZY:
                System.out.println("只要我不努力,老闆就別想過上想要的生活,開擺!");
                break;
            case NORMAL:
                System.out.println("拼搏百天,我要上清華大學!");
                break;
        }
	}
}

//主方法
public static void main(String[] args) {
    Student student = new Student();
    student.setState(State.NORMAL);   //先正常模式
    student.study();

    student.setState(State.LAZY);   //開啟擺爛模式
    student.study();
}

策略模式

和狀態模式代碼一樣。但狀態模式思想是:狀態是先天的設定,就像水不同溫度狀態不同。而策略模式思想是:策略需要根據不同情況制定的。

舉例:簡單的數組排列

//策略介面(模板方法模式)
public interface Strategy {   //策略介面,不同的策略實現也不同

    Strategy SINGLE = Arrays::sort;   //單線程排序方案
    Strategy PARALLEL = Arrays::parallelSort;   //並行排序方案
    
    void sort(int[] array);
}

//排序類
public class Sorter {

    private Strategy strategy;   //策略

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void sort(int[] array){
        strategy.sort(array);
    }
}

//主方法
public static void main(String[] args) {
    Sorter sorter = new Sorter();
    sorter.setStrategy(Strategy.PARALLEL);    //指定為並行排序方案
    
    sorter.sort(new int[]{9, 2, 4, 5, 1, 0, 3, 7});
}

訪問者模式

一件事情,一個訪問介面。訪問者實現該介面,但不同訪問者關心的事情著重點不同

舉例:假如你獲獎了還是國家級一等獎

//獎實體類
public class Prize {   //獎
    String name;   //比賽名稱
    String level;    //等級

    public Prize(String name, String level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public String getLevel() {
        return level;
    }
}

//訪問者介面
public interface Visitor {
    void visit(Prize prize);   //visit方法來訪問我們的獎項
}

//不同訪問者
public class Teacher implements Visitor {   //指導老師作為一個訪問者
    @Override
    public void visit(Prize prize) {   //它只關心你得了什麼獎以及是幾等獎,這也關乎老師的榮譽
        System.out.println("你得獎是什麼獎?"+prize.name);
        System.out.println("你得了幾等獎?"+prize.level);
    }
}

public class Boss implements Visitor{    //你的公司老闆作為一個訪問者
    @Override
    public void visit(Prize prize) {   //你的老闆只關心這些能不能為公司帶來什麼效益,獎本身並不重要
        System.out.println("你的獎項大麽,能夠為公司帶來什麼效益麽?");
        System.out.println("還不如老老實實加班給我多乾乾,別去搞這些沒用的");
    }
}

//主方法
public static void main(String[] args) {
    Prize prize = new Prize("ACM國際大學生程式設計競賽","一等價");
	Teacher teacher = new Teacher();
    Boss boss = new Boss();
    teacher.visit(prize);
    boss.visit(prize);

}

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

-Advertisement-
Play Games
更多相關文章
  • 本文適用於SkyWalking v9.1.0。 SkyWalking簡介 SkyWalking是一個分散式系統的應用程式性能監視(APM)工具,專為微服務、雲原生架構和基於容器(K8s)架構而設計。當前版本具備了全路徑跟蹤、指標採集、日誌記錄等功能,並對多種編程語言及平臺(Java/C/C++/Go ...
  • 1. 新建項目 點擊+號 進入創建場景,選擇對應的選項和自己的AppID 為了不見黃色警告熱重載,可以選擇關閉。 在project.config.json項目的配置文件的setting配置添加如下: "checkSiteMap":false 2. 配置首頁 2.1 新建項目與梳理項目結構 點擊app ...
  • 為了保護用戶隱私,大多數應用只會在前臺運行時獲取用戶位置,當應用在後臺運行時,定位功能會被禁止。這就導致APP在後臺或者鎖屏時無法正常記錄GPS軌跡,這對打車、共用出行、跑步等需要實時記錄用戶軌跡的應用影響非常大,甚至影響了應用核心功能的使用體驗。那對於這些應用的開發者來說,如何在用戶主動授權位置信 ...
  • 今天在學習如何使用npm安裝包的時候,在使用 npm install xxx -g 安裝全局包時, 發現安裝的包無法使用。而安裝時cmd卻沒有報錯,這令我很疑惑,這應該是安裝成功了但卻不能使用。 如下圖所示 在查詢了資料後,使用了 npm root -g 命令,獲得了全局包的安裝路徑,打開後發現該路 ...
  • 使用$parent訪問父級組件實例 點擊打開視頻講解更詳細 和 $root 類似,$parent property 可以用來從一個子組件訪問父組件的實例。它提供了一種機會,可以在後期隨時觸達父級組件,以替代將數據以 prop 的方式傳入子組件的方式。 註意:在絕大多數情況下,觸達父級組件會使得你的應 ...
  • 前端周刊:2022-13 期 前端開發 Vue3 文檔更新 更新後的 Vue3 文檔分別提供了選項式和組合式兩個版本,內容豐富程度和細緻程度也有很大提升,推薦大家重讀一遍。 前端請求併發控制 所有請求都在一個數組中,以限定的併發數將請求發完 前端 API 請求的各種騷操作 併發控制 / 節流控制 / ...
  • 處理邊界情況之使用$root訪問根實例 點擊打開視頻教程 在每個 new Vue 實例的子組件中,其根實例可以通過 $root property 進行訪問。 例如,在這個根實例中: src\main.js import Vue from 'vue' import App from './App.vu ...
  • 本文是深入淺出 ahooks 源碼系列文章的第七篇,該系列已整理成文檔-地址。覺得還不錯,給個 star 支持一下哈,Thanks。 今天我們來聊聊定時器。 useInterval 和 useTimeout 看名稱,我們就能大概知道,它們的功能對應的是 setInterval 和 setTimeou ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...