【設計模式】- 行為型模式2

觀察者模式

定義了一對多的依賴關系,讓多個觀察者對象同時監聽某一個對象主題。這個主題對象在狀態變化時,會通知所有的觀察者對象,讓他們能夠自動更新自己。

主要角色

  • 抽象主題角色:把所有觀察者對象保存在一個集合里,每個主題都可以有任意數量的觀察者,抽象主題提供一個接口,可以添加和刪除觀察者對象
  • 具體主題:該角色將有關狀態存入具體觀察者對象,在具體主題的內部狀態發生改變時,給所有注冊過的觀察者發送通知
  • 抽象觀察者:是觀察者的抽象類,定義了一個更新接口,在主題更改時通知更新自己
  • 具體觀察者:實現抽象觀察者定義的更新接口,以便在得到主題更改時通知更新自身的狀態

案例:微信公眾號

需求】:當這個微信公眾號的專欄發生變更后,所有訂閱了這個微信公眾的用戶都會收到通知。

抽象的觀察者:

public interface Observer {void update(String message);
}

訂閱公眾號的人(具體的觀察者):

@AllArgsConstructor
public class WeiXinUser implements Observer {private String name;@Overridepublic void update(String message) {System.out.println(name + "-" + message);}
}

抽象主題角色:

public interface Subject {// 添加訂閱者(觀察者對象)void attach(Observer observer);// 刪除訂閱者void detach(Observer observer);// 通知訂閱者更新消息void notify(String message);
}

公眾號類(具體主題類):

public class SubscriptionSubject implements Subject {// 定義一個集合,存儲多個觀察者對象private List<Observer> weixinUserList = new ArrayList<>();@Overridepublic void attach(Observer observer) {weixinUserList.add(observer);}@Overridepublic void detach(Observer observer) {weixinUserList.remove(observer);}@Overridepublic void notify(String message) {// 通知所有的觀察者對象去調用觀察者對象的update()方法weixinUserList.forEach(observer -> observer.update(message));}
}

測試類:

public class Client {public static void main(String[] args) {// 1. 創建公眾號對象SubscriptionSubject subject = new SubscriptionSubject();// 2. 訂閱公眾號subject.attach(new WeiXinUser("孫悟空"));subject.attach(new WeiXinUser("豬八戒"));subject.attach(new WeiXinUser("沙僧"));// 3. 公眾號更新,發消息給訂閱者(觀察者對象)subject.notify("專欄更新了");}
}

適用場景

  1. 對象間存在一對多的狀態,一個對象的狀態改變會影響其他對象
  2. 一個抽象模型有兩個方面,其中一個方面依賴于另一個方面

JDK中提供的實現

通過Observable類和Observer接口定義了觀察者模式,只要實現他們的子類就可以編寫觀察者模式實例。

Observable類:抽象主題類

  1. void addObserver(Observer var1)方法:將新的觀察者對象添加到集合中
  2. void notifyObservers(Object var1)方法:調用集合中所有觀察者對象的update()方法,通知他們數據發生變化。(越晚加入集合的越先通知,因為遍歷時從后往前的)
  3. void setChanged()方法:用來設置一個boolean的內部標志,表明目標對象發生變化,當他為true時,notifyObservers()才會通知觀察者

Observer接口:抽象觀察者

監視目標對象的變化,當目標對象發生變化時,觀察者得到通知,并調用update()方法,進行相應的工作。

案例:警察抓小偷

警察是觀察者對象,小偷是被觀察者對象

小偷(被觀察者,需要繼承Observable類):

@Data
@AllArgsConstructor
public class Thief extends Observable {private String name;public void steal() {System.out.println("小偷:我偷東西了");super.setChanged(); // changed = truesuper.notifyObservers(); // 只有把changed改成true,這個方法才會被執行}
}

警察(觀察者類,需要繼承Observer接口):

@Data
@AllArgsConstructor
public class Policeman implements Observer {private String name;@Overridepublic void update(Observable o, Object arg) {System.out.println("警察:" + ((Thief)o).getName() + "抓到你了");}
}

測試類:

public class Client {public static void main(String[] args) {// 創建小偷對象Thief t = new Thief("老王");// 創建警察對象Policeman p = new Policeman("小林");// 讓警察盯著小偷t.addObserver(p); // 訂閱主題(把警察添加到小偷的集合中,小偷偷東西就會通知警察)// 小偷偷東西t.steal();}
}

中介者模式

同事之間的關系是錯綜復雜的(網狀結構)
但是如果引入中介者,就是呈現一種星形結構,所有的對象只需要和中介者有關聯即可。
在這里插入圖片描述

中介者模式:定義一個中介角色來封裝一系列對象之間的交互,使原有對象之間的耦合沖散,且可以獨立改變他們之間的交互

主要角色

  • 抽象中介者角色:中介者的接口(提供同時對象注冊與轉發同時對象信息的抽象方法)
  • 具體中介者角色:實現中介者接口,定義一個List來管理同事對象,協調各個同時角色時間的交互關系
  • 抽象同事類角色:定義同事類的接口,保存中介者對象,提供同時對象交互的抽象方法,實現所有相互影響的同事類的公共功能
  • 具體同事類角色:是抽象同事類的實現者,當需要與其他同事交互時,由中介者對象負責后續的交互

案例:租房

房屋中介(抽象中介者類):

public abstract class Mediator {public abstract void constact(String message, Person person);
}

抽象 租客 or 房主類:

@AllArgsConstructor
public abstract class Person {// 租房者 or 房主的姓名protected String name;// 中介protected Mediator mediator;// 和中介聯系abstract void constact(String message);// 獲取信息abstract void getMessage(String message);
}

具體的租客類:

public class Tenant extends Person {public Tenant(String name, Mediator mediator) {super(name, mediator);}@Overridepublic void constact(String message) {mediator.constact(message, this);}@Overridepublic void getMessage(String message) {System.out.println("租房者" + name + "獲取到的信息:" + message);}
}

具體的房主類:

public class HouseOwner extends Person {public HouseOwner(String name, Mediator mediator) {super(name, mediator);}@Overridevoid constact(String message) {mediator.constact(message, this);}@Overridevoid getMessage(String message) {System.out.println("房主" + name + "獲取到的信息:" + message);}
}

具體的中介者角色:

@Data
public class MediatorStructure extends Mediator {// 房主private HouseOwner houseOwner;// 租房者對象private Tenant tenant;@Overridepublic void constact(String message, Person person) {if(person == houseOwner) { // 房主tenant.getMessage(message);}else{ // 租房者houseOwner.getMessage(message);}}
}

測試類:

public class Client {public static void main(String[] args) {// 1. 創建中介者對象MediatorStructure mediator = new MediatorStructure();// 2. 創建租房者對象Tenant tenant = new Tenant("李四", mediator);// 3. 創建房主對象HouseOwner houseOwner = new HouseOwner("張三", mediator);// 4.中介者知道房主和租房者對象mediator.setTenant(tenant);mediator.setHouseOwner(houseOwner);// 5. 租房者和中介溝通tenant.constact("我要租房"); // 中介者會把這個信息發給房主// 6. 房主回應消息houseOwner.constact("我有房子");}
}

適用場景

  1. 系統中對象之間存在復雜的引用關系
  2. 想創建一個運行于多個類之間的對象(中介者角色),又不想生成新的子類

迭代器模式

提供一個對象來順序訪問聚合對象中的一系列數據,而不暴露聚合對象的內部表示。

主要角色

  • 抽象聚合角色:定義存儲、添加、刪除聚合元素以及創建迭代器對象的接口
  • 具體聚合角色:實現抽象聚合角色,返回具體迭代器實例
  • 抽象迭代器角色:定義訪問和遍歷聚合元素的接口
  • 具體迭代器角色:定義抽象迭代器接口中所定義的方法,完成對聚合對象的遍歷,記錄遍歷的當前位置

案例:學生容器

學生類:

@Data
@AllArgsConstructor
public class Student {private String name; // 姓名private String number; // 學號
}

抽象迭代器角色接口:

public interface StudentIterator {// 判斷是否還有元素boolean hasNext();// 獲取下一個元素Student next();
}

具體迭代器角色類:

public class StudentIteratorImpl implements StudentIterator {private List<Student> list;private int position = 0; // 用來記錄遍歷時的位置public StudentIteratorImpl(List<Student> list) {this.list = list;}@Overridepublic boolean hasNext() {return position < list.size();}@Overridepublic Student next() {return list.get(position++);}
}

抽象聚合角色類:

public interface StudentAggregate {// 添加學生void addStudent(Student student);// 刪除學生void removeStudent(Student student);// 獲取迭代器對象StudentIterator getStudentIterator();
}

具體聚合角色類:

public class StudentAggregateImpl implements StudentAggregate {private List<Student> list = new ArrayList<>();@Overridepublic void addStudent(Student student) {list.add(student);}@Overridepublic void removeStudent(Student student) {list.remove(student);}@Overridepublic StudentIterator getStudentIterator() {return new StudentIteratorImpl(list);}
}

測試類:

public class Client {public static void main(String[] args) {// 1. 創建聚合對象StudentAggregateImpl aggregate = new StudentAggregateImpl();// 2.添加元素aggregate.addStudent(new Student("小林", "001"));aggregate.addStudent(new Student("xiaolin", "002"));aggregate.addStudent(new Student("03", "003"));// 3. 遍歷聚合對象StudentIterator iterator = aggregate.getStudentIterator(); // 獲取迭代器對象while(iterator.hasNext()) { // 判斷是否有元素System.out.println(iterator.next()); // 輸出}}
}

適用場景

  1. 需要為聚合對象提供多種遍歷方式
  2. 需要為遍歷不同的聚合結構提供一個統一的接口
  3. 當訪問一個聚合對象的內容而無需暴露內部細節的表示

JDK源碼解析:Iterator類

List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator();
while(itertaor.hasNext()) {System.out.println(iterator.next());
}

在開發中,如果想使用迭代器模式,只需要讓我們自己實現的類實現java.util.Iterable,并實現其中的iterator()方法,使其返回一個java.util.Iterable的實現類就可以了

訪問者模式

封裝一些作用于某種數據結構中的個元素的操作,可以在不改變數據結構的前提下,定義作用于這些元素的新操作。

主要角色】:

  • 抽象訪問者角色:定義了對每一個元素的訪問行為(訪問者模式要求元素的個數不能改變)
  • 具體訪問者角色:給出對每個元素類訪問時所產生的具體行為
  • 抽象元素角色:定義了一個接受訪問者的方法(accept),每一個元素都要可以被訪問者訪問
  • 具體元素角色:提供接收訪問角色的具體方法
  • 對象結構角色:定義了對象結構,會包含一組元素,可以迭代這些元素,供訪問者使用

案例:給寵物喂食

需求】:要給寵物(狗、貓)喂食的時候,主人可以喂,其他人也可以喂

  • 訪問者角色:給寵物喂食的人
  • 具體訪問者角色:主人、其他人
  • 抽象元素角色:動物抽象類
  • 具體元素角色:寵物狗、寵物貓
  • 結構對象角色:主人家

人(訪問者角色類):

public interface Person {// 給寵物貓喂食void feed(Cat cat);// 給寵物貓喂食void feed(Dog dog);
}

主人、其他人(具體訪問者角色類):

public class Owner implements Person {@Overridepublic void feed(Cat cat) {System.out.println("主人喂食貓");}@Overridepublic void feed(Dog dog) {System.out.println("主人喂食狗");}
}public class Someone implements Person {@Overridepublic void feed(Cat cat) {System.out.println("其他人喂食貓");}@Overridepublic void feed(Dog dog) {System.out.println("其他人喂食狗");}
}

動物類(抽象元素角色類):

public interface Animal {// 接受訪問者訪問的功能void accept(Person person);
}

貓、狗類(具體元素角色類):

public class Cat implements Animal {@Overridepublic void accept(Person person) {person.feed(this);System.out.println("喵喵喵");}
}public class Dog implements Animal {@Overridepublic void accept(Person person) {person.feed(this);System.out.println("汪汪汪");}
}

家(對象結構類):

public class Home {// 存儲元素對象private List<Animal> nodeList = new ArrayList<>();// 添加元素public void add(Animal animal) {nodeList.add(animal);}//public void action(Person person) {// 遍歷集合,獲取每一個元素,讓訪問者訪問每一個元素nodeList.forEach(animal -> animal.accept(person));}
}

測試類:

public class Client {public static void main(String[] args) {// 創建Home對象Home home = new Home();home.add(new Dog());home.add(new Cat());// 創建主人對象Owner owner = new Owner();// 讓主人喂食所有的寵物home.action(owner);}
}

適用場景

對象結構相對穩定,操作算法經常變化

擴展:雙分派技術

分派技術

分派:變量被聲明的類型叫變量的靜態類型,根據對象的類型對方法進行的選擇就是分派。

  1. 動態分派:發生在運行十七,動態分派動態的置換某個方法(方法重寫)
class Animal {public void eat() {}
}
class Dog extends Animal {public void eat() {System.out.println("dog");}
}
class Cat extends Animal {public void eat() {System.out.println("cat");}
}
public class Demo01 {public static void main(String[] args) {Animal a = new Dog();a.eat();a = new Cat();a.eat();}
}
  1. 靜態分派:發生在編譯時期,分派根據靜態類型信息發生(方法重載)
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Execute {public void execute(Animal a) {System.out.println("animal");}public void execute(Dog d) {System.out.println("dog");}public void execute(Cat c) {System.out.println("cat");}
}
public class Demo02 {public static void main(String[] args) {Animal a = new Animal();Animal d = new Dog();Animal c = new Cat();Execute e = new Execute();e.execute(a);// animale.execute(d);// animale.execute(c);// animal}
}

重載方法的分派是在編譯時期進行的,這個分派過程在編譯時期就完成了

雙分派技術

在選擇一個方法時,不僅僅要根據消息接收者的運行時區別,還要根據參數的運行時區別。

class Execute {public void execute(Animal a) {System.out.println("animal");}public void execute(Dog d) {System.out.println("dog");}public void execute(Cat c) {System.out.println("cat");}
}
class Animal {public void accept(Execute e) {e.execute(this);}
}
class Dog extends Animal {public void accept(Execute e) {e.execute(this);}
}
class Cat extends Animal {public void accept(Execute e) {e.execute(this);}
}public class Demo03 {public static void main(String[] args) {Animal a = new Animal();Animal d = new Dog();Animal c = new Cat();Execute e = new Execute();a.accept(e); // animald.accept(e); // dogc.accept(e); // cat}
}

上邊代碼經歷了兩次分派

  1. 第一次分派(方法重寫、靜態分派):客戶端將Execute對象作為參數傳遞給Animal類型的變量調用方法
  2. 第二次分派(方法重載、動態分派):每個類將自己this作為參數傳遞,這里的Execute類中有多個重載的方法,而傳遞的this是具體的實際類型對象

雙分派實現動態綁定的本質:在重載方法委派的前面加上了繼承體系中的覆蓋環節,因為覆蓋是動態的,所以重載就是動態的了。

備忘錄模式

又叫快照模式,在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態,以便以后當需要時能將該對象恢復到原先保存的狀態。

主要角色

  • 發起人角色:記錄當前時刻的內部狀態信息,提供創建、恢復備忘錄的功能
  • 備忘錄角色:負責存儲發起人的內部狀態,在需要的時候提供這些內部狀態給發起人
  • 管理者角色:對備忘錄進行管理,提供保存、獲取備忘錄的功能,不能對備忘錄的內容進行訪問和修改。

案例:游戲挑戰boss

需求】:游戲角色有生命力、攻擊力、防御力等數據,在打boss前后都不一樣,我們允許玩家如果感覺和boss決斗的效果不理想可以讓游戲恢復到快斗之前的狀態

白箱備忘錄模式

備忘錄角色對任何對象都一個一個接口(寬接口),備忘錄角色內部所存儲的對象就對所有對象公開。

游戲角色類(發起人角色):

@Data
public class GameRole {private int vit; // 生命力private int atk; // 攻擊力private int def; // 防御力// 初始化內部狀態public void initState() {this.vit = 100;this.atk = 100;this.def = 100;}// 戰斗public void fight() {this.vit = 0;this.atk = 0;this.def = 0;}// 保存角色狀態功能public RoleStateMemento saveState() {return new RoleStateMemento(vit, atk, def);}// 恢復角色狀態(將備忘錄對象中存儲的狀態賦值給當前成員)public void recoverState(RoleStateMemento memento) {this.vit = memento.getVit();this.atk = memento.getAtk();this.def = memento.getDef();}// 展示狀態public void stateDisplay() {System.out.println("角色生命力" + vit);System.out.println("角色攻擊力" + atk);System.out.println("角色防御力" + def);}}

備忘錄角色類:

@NoArgsConstructor
@AllArgsConstructor
@Data
public class RoleStateMemento {private int vit; // 生命力private int atk; // 攻擊力private int def; // 防御力
}

備忘錄管理對象:

@Data
public class RoleStateCaretaker {// 備忘錄private RoleStateMemento roleStateMemento;
}

測試類:

public class Client {public static void main(String[] args) {// 創建游戲角色對象GameRole gameRole = new GameRole();gameRole.initState(); // 初始數據gameRole.stateDisplay();// 備份內部狀態RoleStateCaretaker caretaker = new RoleStateCaretaker();caretaker.setRoleStateMemento(gameRole.saveState());gameRole.fight(); // 戰斗gameRole.stateDisplay();// 恢復備忘錄gameRole.recoverState(caretaker.getRoleStateMemento());gameRole.stateDisplay();}
}

上邊之所以是白箱備忘錄模式,是因為管理者、客戶端其實都可以拿到備忘錄對象,進而對備忘錄對象里的內容進行操作。

黑箱備忘錄模式

雙重接口:備忘錄角色對發起人對象提供寬接口,對其他對象提供窄接口(將備忘錄類設置成發起人類的成員內部類)

備忘錄接口(對外提供窄接口):

public interface Memento {
}

備忘錄管理對象:

@Data
public class RoleStateCaretaker {// 備忘錄private Memento memento; // 面向接口(返回的是接口,所以在外界是訪問不到里邊的成員的)
}

游戲角色類(發起人角色):

@Data
public class GameRole {private int vit; // 生命力private int atk; // 攻擊力private int def; // 防御力// 初始化內部狀態public void initState() {this.vit = 100;this.atk = 100;this.def = 100;}// 戰斗public void fight() {this.vit = 0;this.atk = 0;this.def = 0;}// 保存角色狀態功能public RoleStateMemento saveState() {return new RoleStateMemento(vit, atk, def);}// 恢復角色狀態(將備忘錄對象中存儲的狀態賦值給當前成員)public void recoverState(Memento memento) {RoleStateMemento roleStateMemento = (RoleStateMemento) memento;this.vit = roleStateMemento.vit;this.atk = roleStateMemento.atk;this.def = roleStateMemento.def;}// 展示狀態public void stateDisplay() {System.out.println("角色生命力" + vit);System.out.println("角色攻擊力" + atk);System.out.println("角色防御力" + def);}// 成員內部類,必須實現Memento接口// 把備忘錄角色類定義在了發起者角色類中,并將它私有@Data@AllArgsConstructor@NoArgsConstructorclass RoleStateMemento implements Memento {private int vit; // 生命力private int atk; // 攻擊力private int def; // 防御力}
}

測試類:

public class Client {public static void main(String[] args) {// 創建游戲角色對象GameRole gameRole = new GameRole();gameRole.initState(); // 初始數據gameRole.stateDisplay();// 備份內部狀態RoleStateCaretaker caretaker = new RoleStateCaretaker();caretaker.setMemento(gameRole.saveState());gameRole.fight(); // 戰斗gameRole.stateDisplay();// 恢復備忘錄gameRole.recoverState(caretaker.getMemento());gameRole.stateDisplay();}
}

把備忘錄角色類定義在了發起者角色類中,并將它私有,這樣外界就不能訪問了

適用場景

  1. 需要保存和恢復數據的場景(玩游戲時的中間結果存檔功能)
  2. 需要提供一個可回滾操作的場景
    • word、記事本按ctrl + z
    • 數據庫中事務操作

解釋器模式

定義一個語言,定義它的文法表示,并定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。

主要角色

  • 抽象表達式角色:約定解釋器的解釋操作(主要包含解釋方法interpret())
  • 終結符表達式角色:抽象表達式的子類,用來標識文法中與終結符相關的操作
  • 非終結符表達式角色:抽象表達式的子類,用來表示文法中與非終結符相關的操作
  • 環境角色:包含各個解釋器需要的數據或公共的功能
  • 客戶端:將需要分析的句子或表達式轉換成使用解釋器對象描述的抽象語法樹

案例:實現加減法的軟件

抽象表達式類:

public abstract class AbstractExpression {public abstract int interpret(Context context);
}

環境角色類:

public class Context {// 定義map集合,存儲變量及對應的值private Map<Variable, Integer> map = new HashMap<>();// 添加變量public void assign(Variable var, Integer value) {map.put(var, value);}// 根據變量獲取對應值public int getValue(Variable var) {return map.get(var);}
}

封裝變量的類:

@Data
@AllArgsConstructor
public class Variable extends AbstractExpression {// 聲明存儲【變量名】的成員變量private String name;@Overridepublic int interpret(Context context) {// 返回變量的值return context.getValue(this);}public String toString() {return name;}
}

減法、加法表達式類

@AllArgsConstructor
@Data
public class Minus extends AbstractExpression {// 加號左邊的表達式private AbstractExpression left;// 加號右邊的表達式private AbstractExpression right;@Overridepublic int interpret(Context context) {// 將左邊表達式的結果和右邊表達式的結果相減return left.interpret(context) - right.interpret(context);}public String toString() {return "(" + left.toString() + " - " + right.toString() + ")";}
}@AllArgsConstructor
@Data
public class Plus extends AbstractExpression {// 加號左邊的表達式private AbstractExpression left;// 加號右邊的表達式private AbstractExpression right;@Overridepublic int interpret(Context context) {// 將左邊表達式的結果和右邊表達式的結果相加return left.interpret(context) + right.interpret(context);}public String toString() {return "(" + left.toString() + " + " + right.toString() + ")";}
}

測試類:

public class Client {public static void main(String[] args) {// 創建環境對象Context context = new Context();// 創建多個變量對象Variable a = new Variable("a");Variable b = new Variable("b");Variable c = new Variable("c");Variable d = new Variable("d");// 將變量存儲到環境中context.assign(a, 1);context.assign(b, 2);context.assign(c, 3);context.assign(d, 4);// 構建抽象語法樹AbstractExpression expression = new Minus(a, new Plus(new Minus(b, c), d));// 解釋(計算)int result = expression.interpret(context);System.out.println(expression + " = " + result);}
}

每條規則都需要定義一個類

適用場景

  1. 問題重復出現,可以用一種簡單的語言來進行表達
  2. 一個語言需要解釋執行,并且語言中的句子可以表示為一個抽象的語法樹

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

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

相關文章

mapbox-gl強制請求需要accessToken的問題

vue引入"mapbox-gl": "^2.15.0", 1.13以后得版本&#xff0c;都強制需要驗證這個mapboxgl.accessToken。 解決辦法&#xff1a;實例化地圖的代碼中&#xff0c;加入這個&#xff1a; const originalFetch window.fetch; window.fetch function ({ url…

已知6、7、8月月平均氣溫和標準差,求夏季季平均溫度與標準差

由下面定理&#xff0c;得出平方和的公式&#xff1a;&#xff08;即每天的溫度平方和&#xff09; 這樣就可以推出季平均的算法&#xff1a; 舉例&#xff1a;在Excel用公式算&#xff0c;不要手算&#xff1a; 因此季平均&#xff1a;(B2*C2B3*C3B4*C4)/SUM(B2:B4) 季標準差…

手機內存不夠,哪些文件可以刪?

1??應用緩存文件 安卓&#xff1a;通過「文件管理器」→「Android」→「data」或「cache」文件夾&#xff08;部分需權限&#xff09;&#xff0c;或直接在應用設置中清除緩存 iOS&#xff1a;無需手動清理&#xff0c;系統會自動管理&#xff0c;或在應用內設置中清除&…

可編輯98頁PPT | 某大型制造業數字化轉型戰略規劃項目方案

薦言摘要&#xff1a;某大型制造業數字化轉型戰略規劃項目方案聚焦企業全價值鏈升級&#xff0c;以“數據驅動業務重塑”為核心&#xff0c;打造行業標桿級數字化能力。項目將分三階段推進&#xff0c;首階段聚焦頂層設計&#xff0c;通過現狀診斷明確痛點&#xff1a;針對企業…

lovart design 設計類agent的系統提示詞解讀

文章目錄 lovart 設計agent介紹角色定義工作規范工具調用任務復雜度指南任務移交指南其他ref lovart 設計agent介紹 lovart作為設計agent&#xff0c;產品功能包括&#xff1a; 全鏈路設計能力&#xff1a;可以快速生成完整的品牌視覺方案&#xff0c;包括標志、配色、品牌規范…

使用 docker-volume-backup 備份 Docker 卷

docker-volume-backup 是一個用于備份 Docker 卷的工具&#xff0c;在 Windows 10 上使用它&#xff0c;你可以按照以下步驟操作&#xff1a; 1. 確保 Docker 環境已安裝并正常運行 在 Windows 10 上&#xff0c;你需要安裝 Docker Desktop for Windows。可以從 Docker 官方網…

用戶行為日志分析的常用架構

## 1. 經典Lambda架構 Lambda架構是一種流行的大數據處理架構&#xff0c;特別適合用戶行為日志分析場景。 ### 1.1 架構組成 Lambda架構包含三層&#xff1a; - **批處理層(Batch Layer)**: 存儲全量數據并進行離線批處理 - **實時處理層(Speed Layer)**: 處理最新數據&…

從API到UI:直播美顏SDK中的濾鏡與貼紙功能開發與落地方案詳解

時下&#xff0c;濾鏡和貼紙功能&#xff0c;已經成為主播們展現個性、增強互動的“必備神器”。那么&#xff0c;這些功能背后的技術實現到底有多復雜&#xff1f;如何從API到UI構建一個流暢、靈活的美顏SDK呢&#xff1f;本文將從底層原理到前端實現&#xff0c;全面解析這兩…

21.EC實戰 嵌入式控制器EC如何進入休眠模式實現低功耗

文章目錄 一、概述1. WUI0中斷向量表配置2. 中斷服務函數內容3. 深度睡眠檢測4. 深度睡眠功能函數4.1 關閉所有中斷4.2 外部中斷對應引腳功能配置4.3 設置喚醒功能和喚醒中斷4.4 進入深度睡眠狀態一、概述 EC作為筆記本電腦的嵌入式控制器,在筆記本電腦使用電池單獨工作時,關…

Java實現PDF加水印功能:技術解析與實踐指南

Java實現PDF加水印功能&#xff1a;技術解析與實踐指南 在當今數字化辦公環境中&#xff0c;PDF文件因其跨平臺兼容性和格式穩定性而被廣泛應用。然而&#xff0c;為了保護文檔的版權、標記文檔狀態&#xff08;如“草稿”“機密”等&#xff09;或增加文檔的可追溯性&#xf…

vue2、vue3項目打包生成txt文件-自動記錄打包日期:git版本、當前分支、提交人姓名、提交日期、提交描述等信息 和 前端項目的版本號json文件

vue2 打包生成text文件 和 前端項目的版本號json文件 項目打包生成txt文件-自動記錄git版本、當前分支、提交人姓名、提交日期、提交描述等信息生成版本號json文件-自動記錄當前版本號、打包時間等信息新建branch-version-webpack-plugin.js文件 // 同步子進程 const execSyn…

Filament引擎(一) ——渲染框架設計

filament是谷歌開源的一個基于物理渲染(PBR)的輕量級、高性能的實時渲染框架&#xff0c;其框架架構設計并不復雜&#xff0c;后端RHI的設計也比較簡單。重點其實在于項目中材質、光照模型背后的方程式和理論&#xff0c;以及對它們的實現。相關的信息&#xff0c;可以參考官方…

洛谷B3876—— [信息與未來 2015] 中間值

見&#xff1a;B3876 [信息與未來 2015] 中間值 - 洛谷 題目描述 給出一個正整數 n&#xff0c;生成長度為 n 的數列 a&#xff0c;其中 ai?i(1≤i≤n)。 若 n 為奇數&#xff0c;則輸出 a 的中間數&#xff08;位于 a 正中位置的數&#xff09;&#xff1b;若 n 為偶數&am…

Java 后端基礎 Maven

Maven 1.什么是Maven 2.Maven的作用 Maven核心 Maven概述 IDEA集成Maven 1.創建Maven項目 點擊設置里的 Project Structure 將jdk和編譯語言進行設置 隨后點擊apply點擊ok 2.Maven坐標 3.導入Maven項目 將文件夾復制到當前項目的目錄下 在這個目錄下&#xff0c;在磁盤中…

qtcreater配置opencv

我配置opencv不管是按照網上的教程還是deep seek發現都有些問題&#xff0c;下面是我的配置方法以及實踐成功的心得 電腦環境 windows平臺qt6 下載 我這里直接提供官網下載地址&#xff1a;https://opencv.org/releases/ 我下載的是最新版&#xff0c;下載后是一個.exe文件…

單片機-STM32部分:15、直流電機與步進電機 PWM/IO

飛書文檔https://x509p6c8to.feishu.cn/wiki/InUfwEeJNimqctkyW1mcImianLh 一、步進電機與直流電機&#xff1a; 1-1、什么是直流電機&#xff1f; 直流電機是最常見的電機類型。直流電動機通常只有兩個引線&#xff0c;一個正極和一個負極。直流電機的轉速控制主要依靠改變輸…

「佰傲再生醫學」攜手企企通,解鎖企業采購供應鏈數字化新體驗

健康&#xff0c;是人類美好生活的基石。隨著“健康中國2030”規劃的深入推進&#xff0c;生物醫藥和再生醫學等前沿技術快速崛起&#xff0c;已成為促進全民健康、提升生命質量的重要支撐&#xff0c;為健康事業注入了新的希望和動力。 一、佰傲再生醫學&#xff0c;讓每個人…

PyTorch Geometric(PyG):基于PyTorch的圖神經網絡(GNN)開發框架

PyTorch Geometric&#xff08;PyG&#xff09;&#xff1a;基于PyTorch的圖神經網絡&#xff08;GNN&#xff09;開發框架 一、PyG核心功能全景圖 PyTorch Geometric&#xff08;PyG&#xff09;是基于PyTorch的圖神經網絡&#xff08;GNN&#xff09;開發框架&#xff0c;專…

亮相戛納電影節、北京電影節的影星

?17日&#xff0c;由高圓圓、古天樂主演的《風林火山》劇組&#xff0c;在第78屆戛納影展上走紅毯亮相&#xff0c;記者爭相拍照&#xff0c;風光無限。 值得關注的是&#xff0c;導演麥浚龍以一身黑色晚禮服踏上紅毯&#xff0c;微笑間顯得躊躇滿志&#xff1b;古天樂則以白色…

Django框架的前端部分使用Ajax請求一

Ajax請求 目錄 1.ajax請求使用 2.增加任務列表功能(只有查看和新增) 3.代碼展示集合 這篇文章, 要開始講關于ajax請求的內容了。這個和以前文章中寫道的Vue框架里面的axios請求, 很相似。后端代碼, 會有一些細節點, 跟前幾節文章寫的有些區別。 一、ajax請求使用 我們先…