圖解設計模式【3】

本系列共分為三篇文章,其中包含的設計模式如下表:

名稱設計模式
圖解設計模式【1】Iterator、Adapter、Template Method、Factory Method、Singleton、Prototype、 Builder、Abstract Factory、 Bridge、 Strategy
圖解設計模式【2】Composite、 Decorator、 Visitor、 Chain of Responsibility、 Facade、 Mediator、 Observer、 Memento
圖解設計模式【3】State、 Flyweight、 Proxy、 Command、 Interpreter、

State模式

State模式中,用類來表示狀態。以類來表示狀態就可以通過切換類來方便地改變對象的狀態。當需要增加新的狀態時,如何修改代碼這個問題也會很明確。

示例

設計一個簡單的報警系統,每秒會改變一次狀態。

金庫報警系統
- 有一個金庫,金庫與報警中心相連,金庫里有警鈴和正常通話用的電話。金庫里有時鐘,監視著現在的時間。
- 白天的時間范圍時9:00-16:59,晚上的時間范圍是17:00-23:59和0:00-8:59。
- 金庫只能在白天使用。白天使用金庫的話,會在報警中心留下記錄;晚上使用金庫的話,會向報警中心發送緊急事態通知。
- 任何時候都可以使用警鈴。使用警鈴的話,會向警報中心發送緊急事態通知。
- 任何時候都可以使用警鈴。使用警鈴的話,會向警報中心發送緊急事態通知。
- 任何時候都可以使用電話(晚上只有留言電話)。白天使用電話的話,會呼叫報警中心。晚上使用電話的話,會呼叫報警中心的留言電話。

如果不使用State模式,我們可以使用如下的偽碼邏輯

警報系統的類{使用金庫時被調用的方法(){if (白天) {向警報中心報告使用記錄} else if (晚上){向警報中心報告緊急事態}警鈴響起時被調用的方法(){向警報中心報告緊急事態}正常通話時被調用的方法(){if (白天){呼叫報警中心} else if (晚上){呼叫警報中心的留言電話}}
}

使用了State模式的偽代碼

表示白天的狀態的類{使用金庫時被調用的方法(){向警報中心報告使用記錄}警鈴響起時被調用的方法(){向警報中心報告緊急事態}正常通話時被調用的方法(){呼叫警報中心}
}
表示晚上的狀態的類{使用金庫時被調用的方法(){向警報中心報告緊急事態}警鈴響起時被調用的方法(){向警報中心報告緊急事態}正常通話時被調用的方法(){呼叫警報中心的留言電話}
}

兩者的區別在于,使用State模式,不需要用if語句判斷是白天還是晚上。

?abstract?
Context
setClock()
changeState()
callSecurityCenter()
recordLog()
SafeFrame
-state
setClock()
changeState()
callSecurityCenter()
recordLog()
?interface?
State
doClock()
doUse()
doAlarm()
doPhone()
DayState
-singleton$
-DayState()
getInstance()
doClock()
doUse()
doAlarm()
doPhone()
NightState
-singleton$
-NightState()
getInstance()
doClock()
doUse()
doAlarm()
doPhone()

State接口時表示金庫狀態的接口。其中包括設置時間、使用金庫、按下警鈴、正常通話等API

public interface State {public abstract void doClock(Context context, int hour);    // 設置時間public abstract void doUse(Context context);                // 使用金庫public abstract void doAlarm(Context context);              // 按下警鈴public abstract void doPhone(Context context);              // 正常通話
}

DayState類表示白天的狀態。該類實現了State接口,因此還實現了State接口中聲明的所有方法。

public class DayState implements State {private static DayState singleton = new DayState();private DayState() {                                // 構造函數的可見性是private}public static State getInstance() {                 // 獲取唯一實例return singleton;}public void doClock(Context context, int hour) {    // 設置時間if (hour < 9 || 17 <= hour) {context.changeState(NightState.getInstance());}}public void doUse(Context context) {                // 使用金庫context.recordLog("使用金庫(白天)");}public void doAlarm(Context context) {              // 按下警鈴context.callSecurityCenter("按下警鈴(白天)");}public void doPhone(Context context) {              // 正常通話context.callSecurityCenter("正常通話(白天)");}public String toString() {                          // 顯示表示類的文字return "[白天]";}
}

NightState類表示晚上的狀態。它與DateState類一樣,也是用了Singleton模式。

public class NightState implements State {private static NightState singleton = new NightState();private NightState() {                              // 構造函數的可見性是private}public static State getInstance() {                 // 獲取唯一實例return singleton;}public void doClock(Context context, int hour) {    // 設置時間if (9 <= hour && hour < 17) {context.changeState(DayState.getInstance());}}public void doUse(Context context) {                // 使用金庫context.callSecurityCenter("緊急:晚上使用金庫!");}public void doAlarm(Context context) {              // 按下警鈴context.callSecurityCenter("按下警鈴(晚上)");}public void doPhone(Context context) {              // 正常通話context.recordLog("晚上的通話錄音");}public String toString() {                          // 顯示表示類的文字return "[晚上]";}
}

Context接口是負責管理狀態和聯系警報中心的接口。

public interface Context {public abstract void setClock(int hour);                // 設置時間public abstract void changeState(State state);          // 改變狀態public abstract void callSecurityCenter(String msg);    // 聯系警報中心public abstract void recordLog(String msg);             // 在警報中心留下記錄
}

SafeFrame類是使用GUI實現警報系統界面的類,它實現了Context接口。

import java.awt.Frame;
import java.awt.Label;
import java.awt.Color;
import java.awt.Button;
import java.awt.TextField;
import java.awt.TextArea;
import java.awt.Panel;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;public class SafeFrame extends Frame implements ActionListener, Context {private TextField textClock = new TextField(60);        // 顯示當前時間private TextArea textScreen = new TextArea(10, 60);     // 顯示警報中心的記錄private Button buttonUse = new Button("使用金庫");      // 金庫使用按鈕private Button buttonAlarm = new Button("按下警鈴");    // 按下警鈴按鈕private Button buttonPhone = new Button("正常通話");    // 正常通話按鈕private Button buttonExit = new Button("結束");         // 結束按鈕private State state = DayState.getInstance();           // 當前的狀態// 構造函數public SafeFrame(String title) {super(title);setBackground(Color.lightGray);setLayout(new BorderLayout());//  配置textClockadd(textClock, BorderLayout.NORTH);textClock.setEditable(false);// 配置textScreenadd(textScreen, BorderLayout.CENTER);textScreen.setEditable(false);// 為界面添加按鈕Panel panel = new Panel();panel.add(buttonUse);panel.add(buttonAlarm);panel.add(buttonPhone);panel.add(buttonExit);// 配置界面add(panel, BorderLayout.SOUTH);// 顯示pack();show();// 設置監聽器buttonUse.addActionListener(this);buttonAlarm.addActionListener(this);buttonPhone.addActionListener(this);buttonExit.addActionListener(this);}// 按鈕被按下后該方法會被調用public void actionPerformed(ActionEvent e) {System.out.println(e.toString());if (e.getSource() == buttonUse) {           // 金庫使用按鈕state.doUse(this);} else if (e.getSource() == buttonAlarm) {  // 按下警鈴按鈕state.doAlarm(this);} else if (e.getSource() == buttonPhone) {  // 正常通話按鈕state.doPhone(this);} else if (e.getSource() == buttonExit) {   // 結束按鈕System.exit(0);} else {System.out.println("?");}}// 設置時間public void setClock(int hour) {String clockstring = "現在時間是";if (hour < 10) {clockstring += "0" + hour + ":00";} else {clockstring += hour + ":00";}System.out.println(clockstring);textClock.setText(clockstring);state.doClock(this, hour);}// 改變狀態public void changeState(State state) {System.out.println("從" + this.state + "狀態變為了" + state + "狀態。");this.state = state; // 給代表狀態的字段賦予表示當前狀態的類的實例,就相當于進行了狀態遷移。}// 聯系警報中心public void callSecurityCenter(String msg) {textScreen.append("call! " + msg + "\n");}// 在警報中心留下記錄public void recordLog(String msg) {textScreen.append("record ... " + msg + "\n");}
}

Main類生成了一個SafeFrame類的實例,并且每秒鐘調用一次setClock方法。

public class Main {public static void main(String[] args) {SafeFrame frame = new SafeFrame("State Sample");while (true) {for (int hour = 0; hour < 24; hour++) {frame.setClock(hour);   // 設置時間try {Thread.sleep(1000);} catch (InterruptedException e) {}}}}
}

解析

  • State

    State表示狀態,定義了根據不同狀態進行不同處理的API。該API是那些處理內容依賴于狀態的方法的集和。

  • ConcreteState

    ConcreteState表示各個具體的狀態,實現了State接口。

  • Context

    Context持有表示當前狀態的ConcreteState。它還定義了提供外部調用者使用State模式的API。

Context
state
requestX()
requestY()
requestZ()
?abstract?
State
methodA()
methodB()
methodC()
methodD()
ConcreteState1
methodA()
methodB()
methodC()
methodD()
ConcreteState2
methodA()
methodB()
methodC()
methodD()

編程時,我們經常使用分而治之的方針。這種方針非常適用于大規模的復雜處理。當遇到龐大且復雜的問題,不能用一般的方法解決時,我們會將該問題分解為多個小問題。在State模式中,我們用類來表示狀態,并為每一種具體的狀態都定義一個相應的類。

State模式易于增加新的狀態,但是在State模式中增加其他“依賴于狀態的處理”是很困難的。

Flyweight模式

Flyweight是輕量級的意思。關于Flyweight模式,一言以蔽之就是“通過盡量共享實例來避免new出實例“。

示例

Uses
creates
Uses
Uses
BigChar
-charname
-fontdate
print()
BigCharFactory
-pool
-singleton$
-BigCharFactory()
getInstacne()
getBigChar()
BigString
-bigchars
print()
Main

BigChar表示大型字符類。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;public class BigChar {// 字符名字private char charname;// 大型字符對應的字符串(由'#' '.' '\n'組成)private String fontdata;// 構造函數public BigChar(char charname) {this.charname = charname;try {BufferedReader reader = new BufferedReader(new FileReader("big" + charname + ".txt"));String line;StringBuffer buf = new StringBuffer();while ((line = reader.readLine()) != null) {buf.append(line);buf.append("\n");}reader.close();this.fontdata = buf.toString();} catch (IOException e) {this.fontdata = charname + "?";}}// 顯示大型字符public void print() {System.out.print(fontdata);}
}

BigCharFactory類是生成BigChar類的實例的工廠。它實現了共享實例的功能。

import java.util.HashMap;public class BigCharFactory {// 管理已經生成的BigChar的實例private HashMap pool = new HashMap();// Singleton模式private static BigCharFactory singleton = new BigCharFactory();// 構造函數private BigCharFactory() {}// 獲取唯一的實例public static BigCharFactory getInstance() {return singleton;}// 生成(共享)BigChar類的實例public synchronized BigChar getBigChar(char charname) {BigChar bc = (BigChar)pool.get("" + charname);if (bc == null) {bc = new BigChar(charname); // 生成BigChar的實例pool.put("" + charname, bc);}return bc;}
}

BigString類是由BigChar組成的大型字符串的類。

public class BigString {// “大型字符”的數組private BigChar[] bigchars;// 構造函數public BigString(String string) {bigchars = new BigChar[string.length()];BigCharFactory factory = BigCharFactory.getInstance();for (int i = 0; i < bigchars.length; i++) {bigchars[i] = factory.getBigChar(string.charAt(i));}}// 顯示public void print() {for (int i = 0; i < bigchars.length; i++) {bigchars[i].print();}}
}

Main類

public class Main {public static void main(String[] args) {if (args.length == 0) {System.out.println("Usage: java Main digits");System.out.println("Example: java Main 1212123");System.exit(0);}BigString bs = new BigString(args[0]);bs.print();}
}

解析

  • Flyweight

    按照通常方式編寫程序會導致程序變重,所以如果能夠共享實例會比較好,而Flyweight表示的就是那些實例會被共享的類。

  • FlyweightFactory

    FlyweightFactory是生成Flyweight的工廠。在工廠中生成Flyweight可以實現共享實例。

  • Client

    Client使用FlyweightFactory來生成Flyweight。

Uses
Uses
Creates
Flyweight
methodA()
methodB()
FlyweightFactory
pool
getFlyweight()
Client

Flyweight模式的主題是共享。在共享實例時,要想到“如果要改變被共享的對象,就會對多個地方產生影響”。在決定Flyweight中的字段時,需要精挑細選。只將那些真正應該在多個地方共享的字段定義在Flyweight中即可。應當共享的信息叫做Intrinsic信息,不應當共享的信息被稱作Extrinsic信息

Command模式

一個類在進行工作時會調用自己或是其他類的方法,雖然調用結果會反映在對象的狀態中,但是并不會留下工作的歷史記錄。這時,如果有一個類用來表示“請進行這項工作”的”命令“,就會方便很多。每一項想知道的工作就不再是”方法的調用“這種動態處理,而是一個表示命令的類的實例,可以用”物“來表示。想管理工作的歷史記錄,只需要管理這些事例的集和即可,而且可以隨時再次執行過去的命令,或是將多個過去的命令整合為一個新命令并執行。

示例

Main
history
canvas
cleaButton
DrawCanvas
history
color
radius
draw()
paint()
?interface?
Drawable
draw()
DrawCommand
drawable
position
execute()
MacroCommand
commands
execute()
append()
undo()
clear()
?interface?
Command
execute()

Command接口時表示命令的接口。在該接口中只定義了一個方法,即execute。至于調用execute方法后具體會進行什么樣的處理,則取決于實現了Command接口的類。

package command;public interface Command {public abstract void execute();
}

MacroCommand類表示由多條命令整合成的命令。該類實現了Command接口。

package command;import java.util.Stack;
import java.util.Iterator;public class MacroCommand implements Command {// 命令的集合private Stack commands = new Stack();// 執行public void execute() {Iterator it = commands.iterator();while (it.hasNext()) {((Command)it.next()).execute();}}// 添加命令public void append(Command cmd) {if (cmd != this) {commands.push(cmd);}}// 刪除最后一條命令public void undo() {if (!commands.empty()) {commands.pop();}}// 刪除所有命令public void clear() {commands.clear();}
}

DrawCommand類實現了Command接口,表示繪制一個點的命令。

package drawer;import command.Command;
import java.awt.Point;public class DrawCommand implements Command {// 繪制對象protected Drawable drawable;// 繪制位置private Point position;// 構造函數public DrawCommand(Drawable drawable, Point position) {this.drawable = drawable;this.position = position;}// 執行public void execute() {drawable.draw(position.x, position.y);}
}

Drawable接口是表示繪制對象的接口。draw方法是用于繪制的方法。

package drawer;public interface Drawable {public abstract void draw(int x, int y);
}

DrawCanvas實現了Drawable接口。

package drawer;import command.*;import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;public class DrawCanvas extends Canvas implements Drawable {// 顏色private Color color = Color.red;// 要繪制的圓點的半徑private int radius = 6;// 命令的歷史記錄private MacroCommand history;// 構造函數public DrawCanvas(int width, int height, MacroCommand history) {setSize(width, height);setBackground(Color.white);this.history = history;}// 重新全部繪制public void paint(Graphics g) {history.execute();}// 繪制public void draw(int x, int y) {Graphics g = getGraphics();g.setColor(color);g.fillOval(x - radius, y - radius, radius * 2, radius * 2);}
}

Main是啟動程序的類。

import command.*;
import drawer.*;import java.awt.*;
import java.awt.event.*;
import javax.swing.*;public class Main extends JFrame implements ActionListener, MouseMotionListener, WindowListener {// 繪制的歷史記錄private MacroCommand history = new MacroCommand();// 繪制區域private DrawCanvas canvas = new DrawCanvas(400, 400, history);// 刪除按鈕private JButton clearButton  = new JButton("clear");// 構造函數public Main(String title) {super(title);this.addWindowListener(this);canvas.addMouseMotionListener(this);clearButton.addActionListener(this);Box buttonBox = new Box(BoxLayout.X_AXIS);buttonBox.add(clearButton);Box mainBox = new Box(BoxLayout.Y_AXIS);mainBox.add(buttonBox);mainBox.add(canvas);getContentPane().add(mainBox);pack();show();}// ActionListener接口中的方法public void actionPerformed(ActionEvent e) {if (e.getSource() == clearButton) {history.clear();canvas.repaint();}}// MouseMotionListener接口中的方法public void mouseMoved(MouseEvent e) {}public void mouseDragged(MouseEvent e) {Command cmd = new DrawCommand(canvas, e.getPoint());history.append(cmd);cmd.execute();}// WindowListener接口中的方法public void windowClosing(WindowEvent e) {System.exit(0);}public void windowActivated(WindowEvent e) {}public void windowClosed(WindowEvent e) {}public void windowDeactivated(WindowEvent e) {}public void windowDeiconified(WindowEvent e) {}public void windowIconified(WindowEvent e) {}public void windowOpened(WindowEvent e) {}public static void main(String[] args) {new Main("Command Pattern Sample");}
}

解析

Creates
Receiver
action()
ConcreteCommand
receiver
execute()
Client
?abstract?
Command
execute()
Invoker
  • Command

    Command負責定義命令的API。

  • ConcreteCommand

    ConcreteCommand負責實現在Command中定義的API。

  • Reciever

    Receiver是Command執行命令時的對象,可以稱之為命令接收者。

  • Client

    Client負責生成ConcreteCommand并分配了Receiver。

  • Invoker

    Invoker是開始執行命令的角色,它會調用在Command中定義的API。

命令的目的不同,應該包含的信息也不同。比如DrawCommand中包含了要繪制的點的位置信息,但不包含點的大小、顏色和形狀等信息。

示例中,MacroCommand的實例代表了繪制的歷史記錄。在該字段中保存了之前所有的繪制信息。如果我們將他保存為文件,就可以永久保存歷史記錄。

Interpreter模式

Interpreter模式中,程序要解決的問題會被用非常簡單的”迷你語言“表述出來,即用”迷你語言“編寫的”迷你程序“把具體的問題表述出來。迷你程序是無法單獨工作的,還需要用java編寫一個負責”翻譯”的程序。翻譯程序會理解迷你語言,并解釋和運行迷你程序。這段翻譯程序被稱為解釋器

示例

Creates
Uses
Main
Context
nextToken()
currentToken()
skipToken()
currentNumber()
?abstract?
Node
parser()
ProgramNode
commandListNode
parse()
RepeatCommandNode
number
commandListNode
parse()
commandListNode
list
parse()
CommandNode
node
parse()
PrimitiveCommandNode
name
parse()
CommandListNode

Node類是語法樹中各個部分中最頂層的類。在Node中只聲明了一個parse抽象方法,該方法用于進行語法解析處理。

public abstract class Node {public abstract void parse(Context context) throws ParseException;
}

ProgramNode類表示程序<program>

// <program> ::= program <command list>
public class ProgramNode extends Node {private Node commandListNode;public void parse(Context context) throws ParseException {context.skipToken("program");commandListNode = new CommandListNode();commandListNode.parse(context);}public String toString() {return "[program " + commandListNode + "]";}
}

CommandListNode表示<command list>

import java.util.ArrayList;// <command list> ::= <command>* end
public class CommandListNode extends Node {private ArrayList list = new ArrayList();public void parse(Context context) throws ParseException {while (true) {if (context.currentToken() == null) {throw new ParseException("Missing 'end'");} else if (context.currentToken().equals("end")) {context.skipToken("end");break;} else {Node commandNode = new CommandNode();commandNode.parse(context);list.add(commandNode);}}}public String toString() {return list.toString();}
}

CommandNode表示<command>

// <command> ::= <repeat command> | <primitive command>
public class CommandNode extends Node {private Node node;public void parse(Context context) throws ParseException {if (context.currentToken().equals("repeat")) {node = new RepeatCommandNode();node.parse(context);} else {node = new PrimitiveCommandNode();node.parse(context);}}public String toString() {return node.toString();}
}

RepeatCommandNode表示<repeat command>

// <repeat command> ::= repeat <number> <command list>
public class RepeatCommandNode extends Node {private int number;private Node commandListNode;public void parse(Context context) throws ParseException {context.skipToken("repeat");number = context.currentNumber();context.nextToken();commandListNode = new CommandListNode();commandListNode.parse(context);}public String toString() {return "[repeat " + number + " " + commandListNode + "]";}
}

PrimitiveCommandNode表示 <primitive command>

// <primitive command> ::= go | right | left
public class PrimitiveCommandNode extends Node {private String name;public void parse(Context context) throws ParseException {name = context.currentToken();context.skipToken(name);if (!name.equals("go") && !name.equals("right") && !name.equals("left")) {throw new ParseException(name + " is undefined");}}public String toString() {return name;}
}

Context類提供了語法解析所必須的方法。

import java.util.*;public class Context {private StringTokenizer tokenizer;private String currentToken;public Context(String text) {tokenizer = new StringTokenizer(text);nextToken();}public String nextToken() {if (tokenizer.hasMoreTokens()) {currentToken = tokenizer.nextToken();} else {currentToken = null;}return currentToken;}public String currentToken() {return currentToken;}public void skipToken(String token) throws ParseException {if (!token.equals(currentToken)) {throw new ParseException("Warning: " + token + " is expected, but " + currentToken + " is found.");}nextToken();}public int currentNumber() throws ParseException {int number = 0;try {number = Integer.parseInt(currentToken);} catch (NumberFormatException e) {throw new ParseException("Warning: " + e);}return number;}
}

ParseException類是表示語法解析時可能發生異常的類。

public class ParseException extends Exception {public ParseException(String msg) {super(msg);}
}

Main類是啟動解釋器的程序。

import java.util.*;
import java.io.*;public class Main {public static void main(String[] args) {try {BufferedReader reader = new BufferedReader(new FileReader("program.txt"));String text;while ((text = reader.readLine()) != null) {System.out.println("text = \"" + text + "\"");Node node = new ProgramNode();node.parse(new Context(text));System.out.println("node = " + node);}} catch (Exception e) {e.printStackTrace();}}
}

解析

  • AbstractExpression

    AbstractExpression定義了語法樹節點的共同APi。

  • TerminalExpression

    TerminalExpression對應BNF中的終結符表達式。

  • NonterminalExpression

    NonterminalExpression對應BNF中的非終結符表達式。

  • Context

    Context為解釋器進行語法解析提供了必要的信息。

  • Client

    為了推導語法樹,Client會調用TerminalExpression和NonteminalExpression。

Creates
Uses
Client
Context
getInfoInterpreter()
?abstract?
AbstractExpression
interpret()
TerminalExpression
interpret()
NonterminalExpression
childExpressions
interpret()

迷你語言包括:正則表達式、檢索表達式、批處理語言等。

Reference

圖解設計模式 【日】結成浩 著 楊文軒 譯

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96661.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96661.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96661.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(純新手教學)計算機視覺(opencv)實戰十四——模板與多個對象匹配

圖片旋轉、圖片鏡像相關教學&#xff1a; &#xff08;純新手教學&#xff09;計算機視覺&#xff08;opencv&#xff09;實戰十三——圖片旋轉、圖片鏡像 的幾種常用方法-CSDN博客https://blog.csdn.net/2302_78022640/article/details/151356600?spm1011.2415.3001.5331 模板…

Java面試核心知識點總結:Redis與MySQL高可用、高并發解決方案

在分布式系統開發中&#xff0c;高并發場景下的數據一致性、系統可用性以及性能優化始終是核心挑戰。本文基于Java技術棧&#xff0c;結合Redis與MySQL的工程實踐&#xff0c;系統梳理分布式系統設計的關鍵技術要點。一、Redis集群架構演進與高可用實踐1.1 主從哨兵模式部署方案…

R 語言科研繪圖第 72 期 --- mantel檢驗圖

在發表科研論文的過程中&#xff0c;科研繪圖是必不可少的&#xff0c;一張好看的圖形會是文章很大的加分項。 為了便于使用&#xff0c;本系列文章介紹的所有繪圖都已收錄到了 sciRplot 項目中&#xff0c;獲取方式&#xff1a; R 語言科研繪圖模板 --- sciRplothttps://mp.…

4.2-中間件之MySQL

4.2.1MySQL的基本知識SQL語句用于存取數據以及查詢、更新和管理關系數據庫系統。包括&#xff1a;DQL&#xff08;select&#xff09;、DML&#xff08;insert,update,delete&#xff09;、DDL&#xff08;create,alter,drop&#xff09;、DCL&#xff08;grant,revoke&#xf…

LVS + Keepalived 高可用負載均衡集群

目錄 一、核心組件與作用 1. LVS&#xff08;Linux Virtual Server&#xff09; 2. Keepalived 二、DR 模式下的 LVS Keepalived 工作原理 1. 整體架構 2. 數據包流向&#xff08;DR 模式&#xff09; 三、部署步驟&#xff08;DR 模式&#xff09; 3.1 環境規劃 3.2…

知識沉淀過于碎片化如何形成體系化框架

要將過于碎片化的知識沉淀轉變為體系化的框架&#xff0c;必須采取一套自上而下設計與自下而上歸集相結合的系統性方法&#xff0c;其核心路徑在于首先進行戰略性診斷與頂層藍圖設計、其次構建統一且可擴展的知識架構&#xff08;分類與標簽體系&#xff09;、然后實施系統性的…

XLua教程之C#調用Lua

上一篇文章 XLua教程之入門篇-CSDN博客 在C#腳本中訪問lua全局數據&#xff0c;特別是table以及function&#xff0c;代價比較大&#xff0c;建議盡量少做相關操作。 LuaEnv.Global.Get 用于獲取一個全局變量&#xff0c;但是無法獲取局部變量(用local修飾) 全局基本類型變量…

C++ 標準庫中的哈希函數:從std::hash到自定義哈希器

C 標準庫中的哈希函數&#xff1a;從 std::hash 到自定義哈希器 1. 引言 在上一篇中&#xff0c;我們介紹了哈希表為什么能夠實現 O(1) 查找。 核心秘密在于&#xff1a;哈希函數。 在 C 標準庫中&#xff0c;哈希表容器&#xff08;如 unordered_map、unordered_set&#xff0…

在圖形 / 游戲開發中,為何 Pixels Per Unit(PPU)數值越小,物體在屏幕上顯示的尺寸越大?

1. 什么是 PPU&#xff1f; PPU&#xff08;Pixels Per Unit&#xff09;指的是 多少像素對應游戲世界中的一個單位&#xff08;Unit&#xff09;。 在 Unity 等游戲引擎中&#xff0c;1 Unit 通常被視為世界空間的基本長度&#xff0c;比如 1 米。2. PPU 與物體大小的關系PPU …

【ZYNQ開發篇】Petalinux和電腦端的靜態ip地址配置

使用Petalinux工具為ZYNQ板卡搭建嵌入式Linux操作系統&#xff0c;成功搭建后&#xff0c;用戶通常會使用客戶端軟件對ZYNQ板卡上的Linux系統進行訪問&#xff0c;軟件需要知道ZYNQ板卡的ip地址才能進行訪問&#xff0c;如果ip地址是動態變化的&#xff0c;軟件每次訪問都要重新…

AVL樹知識總結

AVL樹概念性質一顆AVL樹或是空樹&#xff0c;或者具有一下性質的二叉搜索樹&#xff1a;左右都是AVL樹&#xff0c;左右子樹高度差的絕對值不超過1AVL樹有n個結果&#xff0c;高度保持在O&#xff08;logN&#xff09; 搜索時間復雜度O(logN&#xff09;模擬實現插入定義&#…

返利app的跨域問題解決方案:CORS與反向代理在前后端分離架構中的應用

返利app的跨域問題解決方案&#xff1a;CORS與反向代理在前后端分離架構中的應用 大家好&#xff0c;我是阿可&#xff0c;微賺淘客系統及省賺客APP創始人&#xff0c;是個冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在返利APP的前后端分離架構中&#xff0c;跨…

【dl】python基礎 深度學習中需要用到的python基礎

直接在jupyter寫筆記然后導出md格式真的太好用了本文筆記來自小破站視頻BV1K14y1c75ePython 基礎 1. 變量 1.1 三種基本變量類型 # 字符串 str str_v "123"# 數字 int或float num_v 11 float_v 12.0# 布爾型 bool bool_v True1.1.1 字符串 f字符串&#xff1a;在…

Vue FullPage.js 完整使用指南:Vue 3 官方全屏滾動解決方案

概述 vue-fullpage.js 是 FullPage.js 的官方 Vue.js 3 包裝器&#xff0c;為 Vue 3 應用提供了強大的全屏滾動功能。該插件基于成熟的 FullPage.js 庫&#xff0c;支持多種滾動效果和豐富的配置選項&#xff0c;特別適用于企業級數據大屏、產品展示、單頁應用等場景。 官方信…

軟件工程實踐一:Git 使用教程(含分支與 Gitee)

文章目錄目標一、快速上手1. Windows 安裝 Git2. 初始化 / 克隆二、核心概念速覽三、常用命令清單1) 查看狀態與差異2) 添加與提交3) 歷史與回溯4) 撤銷與恢復&#xff08;Git 2.23 推薦新命令&#xff09;5) 忽略文件四、分支與合并&#xff08;Branch & Merge&#xff09…

css`min()` 、`max()`、 `clamp()`

min() 用來計算多個數值中最小的那個&#xff0c;非常適合做自適應。 width: min(50vw, 500px) 50vw 表示 視口寬度的 50% 500px 表示 500px min(50vw, 500px) 表示會取兩者中 最小的那個 作為最終的寬度&#xff0c;。 使用場景 限制某個元素寬度不超過某個值&#xff1b; 響…

【WRF-VPRM 預處理器】HEG 安裝(服務器)-MRT工具替代

目錄 HEG 安裝 驗證 HEG 安裝與否 設置環境變量(建議) 命令行接口(Command Line Interface) hegtool 工具 hegtool 用法 Header File 格式 功能1:`gdtif` 工具 – MISR 數據處理 `gdtif` 使用方式 參數文件格式(Parameter File Format) 功能2:`resample` 工具 – 重采樣…

PyTorch 神經網絡

神經網絡是一種模仿人腦神經元鏈接的計算模型&#xff0c; 由多層節點組成&#xff0c; 用于學習數據之間的復雜模式和關系。神經網絡通過調整神經元之間的連接權重來優化預測結果&#xff0c;這個過程可以涉及到向前傳播&#xff0c;損失計算&#xff0c;反向傳播和參數更新。…

詳細解析蘋果iOS應用上架到App Store的完整步驟與指南

&#x1f4f1;蘋果商店上架全流程詳解 &#x1f469;?&#x1f4bb;想要將你的App上架到蘋果商店&#xff1f;跟隨這份指南&#xff0c;一步步操作吧&#xff01; 1?? 申請開發者賬號&#xff1a;訪問蘋果開發者網站&#xff0c;注冊并支付99美元年費&#xff0c;獲取開發者…

三維GIS開發實戰!Cesium + CZML 實現火箭飛行與分離的 3D 動態模擬

CZML是一種基于JSON的數據格式&#xff0c;專門用于在Cesium中描述3D場景和時間動態數據。本文將詳細介紹了CZML的特點&#xff08;JSON格式、時間動態性、層次結構等&#xff09;和基本組件&#xff0c;并給出了一個火箭發射的實例。通過搭建Cesium開發環境&#xff08;使用vi…