当前位置: 首页 > news >正文

《HeadFirst设计模式》笔记(上)

设计模式的目录:
在这里插入图片描述

1 设计模式介绍

要不断去学习如何利用其它开发人员的智慧与经验。学习前人的正统思想。
我们认为《Head First》的读者是一位学习者。
一些Head First的学习原则:

  • 使其可视化
  • 将文字放在相关图形内部或附近,而不是放在底部或另一页上,这样学习者解决问题的能力可提高至两倍。
  • 采用对话式和个人化的风格
  • 让学习者进行更深入的思考。引起读者的好起,促进、要求并鼓励读者去解决问题、得出结论、产生新的知识。
  • 吸引并保持读者的注意力
  • 触动他们的情感。如果是读者关心的东西,那么读者就能够记得住。

可以用下面的方法让大脑更好地吸收知识:

  • 1、慢一点,理解得越多,需要记的就越少
  • 2、勤做练习,自己记笔记
  • 3、阅读“There are no Dumb Questions”部分。书中这些部分绝对是核心内容。
  • 4、上床睡觉前不要再看别的书,或者至少不再看其他有难度的东西
  • 5、多喝水
  • 6、大声说出来
  • 7、听听大脑怎么说。注意一下你的大脑是不是负荷太重了,如果发现自己开始浮光掠影地翻看,或者刚看的东西就忘了,这说明该休息一会儿了。
  • 8、要有点感觉。要真正融入到书中的故事里,为书里照片加上自己的说明。
  • 9、设计一些东西。将学来的知识应用到新项目中,甚至重构旧项目。

我们的图表风格类似于UML——尽管我们尽力遵守UML规范,但有时会为了艺术效果而略微打破规则,这往往是出于我们自身的美学考量。

书里的实践活动不是可有可无的。

我们使用“组合”这个词是在广义的面向对象(OO)意义上,这比严格意义上的UML“组合”更加灵活。当我们说‘一个对象是由另一个对象组合而成’时,我们的意思是它们之间存在一种‘包含’(HAS-A)关系。

在面向对象(OO)系统中,类通常表示既有状态(即实例变量)又有行为(即方法)的事物。在这个特定的情况下,事物实际上就是一种行为。然而,即使是行为也可以拥有自己的状态和方法;例如,飞行行为可能包含表示飞行特性的实例变量,如每分钟翼拍次数、最大飞行高度和速度等。

第一个设计原则:
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

将一些可能需要变化之处委托给别人处理,而不是使用定义在Duck类内的呱呱叫和飞行方法。
委托具体通过动态绑定来实现。

在这里插入图片描述

第二个设计原则:针对接口编程,而不是针对实现编程。

第三个设计原则:多用组合,少用继承。

软件开发后相比软件开发前需要更多的时间,因为需要花许多时间在系统的维护和变化上。

定义策略模式

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
策略模式就是前面说的这么多的结合。

在这里插入图片描述
设计模式为您提供了一个与其他开发人员共享的词汇表。一旦你有了词汇表,你就可以更容易地与其他开发人员交流,并激励那些不知道模式的人开始学习它们。

设计模式不会直接进入代码中,而是先进入大脑中。一旦先在脑海中装入了许多关于模式的知识,就能够开始在新设计中采用它们,并当旧代码变得十分混乱时,可用它们重做旧代码。

良好的OO设计必须具备可复用、可扩充、可维护三个特性。

2 观察者模式

观察者模式可以让你的对象知悉现况。
观察者模式是JDK中使用最多的模式之一。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

定义观察者模式:类图

在这里插入图片描述
一对多的关系。一则是提供数据的,多则是观察者。
需要注册观察者和移除观察者可以理解,
NotifyObserver则是用于在状态改变时更新所有当前观察者。

第四个设计原则:为了交互对象之间的松耦合设计而努力。

在这里插入图片描述

在这里插入图片描述
setChanged()方法用来标记状态已经改变的事实,好让notify0bservers0)知道当它被调用时应该更新观察者。如果调用notify0bserversO之前没有先调用setChangedO,观察者就“不会”被通知。Observable 内部:
在这里插入图片描述
通过使用setChanged()方法则可以控制WeatherData对象通知观察者的频率。

import java.util.Observable;
import java.util.Observer;public class ForecastDisplay implements Observer, DisplayElement{private float currentPressure = 29.92f;private float lastPressure;public ForecastDisplay(Observable observable) {WeatherData weatherData = (WeatherData) observable;observable.addObserver(this);}public void update(Observable observable, Object arg) {if (observable instanceof WeatherData) {lastPressure = currentPressure;currentPressure = WeatherData.getPressure();display();}}public void display() {// 在这里显示代码}
}

观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
在这里插入图片描述
观察者模式将固定的addObserver、deleteObserver、notifyObservers、setChange放到类里面,而update抽离出来为接口。

针对接口编程则是体现在:主题与观察者都使用接口。观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。这样可以让两者之间运行正常,又同时具有松耦合的优点。

多用组合体现在:(GeneralDisplay有一个Observable。)观察者模式利用“组合”将许多观察者组合进主题中。对象之间的这种关系不是通过继承产生的,而是在运行时利用组合的方式而产生的。

3 装饰者模式

在这里插入图片描述
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一样地开放(能够扩展)。

第五个设计原则:类应该对扩展开放,对修改关闭。
对扩展开放,对修改关闭的理解:有一些OO技巧,运行系统在不修改代码的情况下进行功能扩展。例如,观察者模式可以在任何时候扩展Subject(主题),而且不需向主题中添加代码。

认识装饰者模式:我们要以饮料为主体,然后在运行时以调料来“装饰”饮料。比方说,如果顾客要摩卡和奶泡深培咖啡,要做的是:
1、拿一个深培咖啡(DarkRoast)对象
2、以摩卡(Mocha)对象装饰它
3、以奶泡(Whip)对象装饰它
4、调用cost()方法,并依赖委托(delegate)将调料的价钱加上去
在这里插入图片描述
一些属性:

  • 装饰者和被装饰者对象有相同的超类型。
  • 可以用一个或多个装饰者包装一个对象。
  • 既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装)的场合,都可以用装饰过的对象代替它。
  • 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
  • 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地使用你喜欢的装饰者来装饰对象。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
画出来的图是这样的(简单画了两个摩卡):
在这里插入图片描述
在这里插入图片描述

# SoyWhip的代码:
public class Soy extends CondimentDecorator {Beverage beverage;public Soy(Beverage beverage) {this.beverage = beverage;}public String getDescription() {return beverage.getDescription() + ", Soy";}public double cost() {return 0.15 + beverage.cost();}
}public class Whip extends CondimentDecorator {Beverage beverage;public Whip(Beverage beverage) {this.beverage = beverage;}public String getDescription() {return beverage.getDescription() + ", Whip";}public double cost() {return 0.15 + beverage.cost();}
}

供应咖啡:
在这里插入图片描述

在这里插入图片描述
装饰者的缺点:采用装饰者实例化组件时,将增加代码的复杂度。一旦使用了装饰器,不仅需要实例化组件,还需要用不确定数量的装饰器将其包裹。

在这里插入图片描述

4 工厂模式

烘烤OO的精华:这句话在比喻性地谈论将面向对象编程的原则和优点应用到某个过程或项目中,就像在烘焙中加入优质的原料一样,来提升最终产品的质量。
在这里插入图片描述

在这里插入图片描述
把这部分抽离出来,当需要比萨时,就叫比萨工厂做一个。(实际上这就叫做简单工厂模式)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如何利用比萨工厂方法订购比萨:
在这里插入图片描述
在这里插入图片描述
平行的类层级:
在这里插入图片描述

定义工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法把类实例化推迟到子类。

在这里插入图片描述
第六个设计原则:要依赖于抽象,不要依赖于具体类。
(这里的“依赖于”其实就是有一个。)
这个原则提倡软件模块之间的依赖关系应该建立在抽象之上,而不是具体的实现类。这样做可以提高代码的灵活性、可维护性和可扩展性,使得系统更易于管理复杂性,并支持变更而不影响依赖它的其他模块。
应用工厂方法之后,类图看起来就像这样:
在这里插入图片描述
避免在OO设计中违反依赖倒置原则的指导方针:

  • 变量不可以持有具体类的引用
  • 不要让类派生自具体类
  • 不要覆盖基类中已实现的方法
    在这里插入图片描述

定义抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5 单例模式

单例模式:用来创建独一无二对象的门票,这类对象仅有一个实例。
有一些对象只需要一个,比如说:线程池(threadpool)、缓存(cache)、对话框、处理偏好设置和注册表(registry)的对象、日志对象,充当打印机、显卡等设备的驱动程序的对象。
关键:如何保证一个对象只能被实例化一次。

C++实现单例设计模式:(将构造函数定义为私有成员,然后在静态成员函数进行实例化和返回)

#include <iostream>
#include <mutex>class Singleton {
private:// 私有构造函数,防止外部创建实例Singleton() {// 可以初始化一些资源}// 删除拷贝构造函数和赋值操作符,防止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:// 静态成员函数,作为全局访问点static Singleton* getInstance() {// 使用局部静态变量来保证线程安全(C++11及以上)static Singleton instance;return &instance;}// 示例方法void showMessage() const {std::cout << "Hello, I'm a Singleton!" << std::endl;}
};// 使用示例
int main() {// 获取单例对象Singleton* singleton = Singleton::getInstance();// 调用单例对象的方法singleton->showMessage();return 0;
}

帮Choc-O-Holic改进CholcolateBoiler类:

public class CholcolateBoiler {private boolean empty;private boolean boiled;public static CholcolateBoiler uniqueInstance;private CholcolateBoiler() {empty = true;boiled = false;}public static CholcolateBoiler getInstance() {if(uniqueInstance == null) {uniqueInstance = new CholcolateBoiler;}return uniqueInstance;}public void fill() {if(isEmpty()) {empty = false;boiled = false;}}
}

定义单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点。

能改善多线程吗?
1、如果getInstance()的性能对应用程序不是很关键,就什么都别做
如果可以接受getInstance()造成的额外负担,就不要管了。
2、改为预先创建实例,而不是延迟创建实例。
在这里插入图片描述
3、用“双重检查加锁”,在getInstance()中减少使用同步
利用双重检查加锁,首先检查实例是否已经创建了,如果尚未创建,才进行同步。
在这里插入图片描述
是否可以创建一个类,把所有的方法和变量都定义为静态的,把类直接当做一个单件?
如果类自给自足,而且不依赖于复杂的初始化,那么可以。但是,因为静态初始化的控制权是在Java手中,这么做有可能导致混乱,特别是当有许多类牵涉其中时。这么做常常会造成一些微妙的、不容易发现的和初始化的次序有关的bug。除非有绝对的必要使用类的单例,否则还是建议使用对象的单例。

6 封装调用

把封装带到一个全新的境界:把方法调用封装起来。
利用命令对象,把请求封装成一个特定对象。如果对每个按钮都存储一个命令对象,那么当按钮被按下的时候,就可以请命令对象做相关的工作。

在这里插入图片描述
答案是这个:
在这里插入图片描述

GarageDoorOpenCommand类:

public class GarageDoorOpenCommand implements Command {GarageDoor garageDoor;public class GarageDoorOpenCommand(GarageDoor garageDoor) {this.garageDoor = garageDoor;}public void execute() {garageDoor.up();}
}

定义命令模式

命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
在这里插入图片描述

在这里插入图片描述
写文档:
在这里插入图片描述
使用宏命令:
需要关闭按钮的命令,代码如下:

LightOffCommand lightOff = new LightOffCommand(light);
StereoOffCommand stereoOff = new StereoOffCommand(light);
TVOffCommand tvOff = new TVOffCommand(tv);
HottubOffCommand hottubOff = new HottubOffCommand(hottub);
public void undo() {for (int i = 0; i < commands.length; i++) {commands[i].undo();}
}

命令模式的更多用途:队列请求
命令可以将运算块打包(一个接收者和一组动作),然后将它传来传去,就像是一般的对象一样。利用这样的特性衍生一些应用,例如:日程安排、线程池、工作队列等。
你认为Web服务器如何应用这样的队列方式?还能想到任何其他的应用吗?

命令模式用于日志请求:通过新增两个方法(store()、load())来实现。

7 适配器模式与外观模式

在这里插入图片描述

在这里插入图片描述
客户使用适配器的过程如下:
1、客户通过目标接口调用适配器的方法对适配器发出请求。
2、适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口。
3、客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。

public class DuckAdapter implements Turkey {Duck duck;public DuckAdapter(Duck duck) {this.duck = duck;}public void gobble() {duck.quack();}public void fly() {duck.fly();}
}

适配器模式的工作是将一个接口转换成另一个。外观模式:让一个适配器包装多个被适配者。

定义适配器模式

适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
在这里插入图片描述
类适配器通过多重继承来实现。
对象适配器利用组合的方式将请求传送给被适配器。

在这里插入图片描述

在这里插入图片描述
外观模式:例如,想要看电影,只要调用一个方法(就是watchMovie())就可以了。灯光、DVD播放器、投影机、功放、屏幕、爆米花,一口气全部搞定。

定义外观模式

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

第七个设计原则:最少知识原则:只和你的密友谈话。

如何不要赢得太多的朋友和影响太多的对象。
就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身
  • 被当做方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 对象的任何组件
    在这里插入图片描述

8 封装算法

模板方法模式:在一个方法中定义一个算法的股价,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
在这里插入图片描述
第八个设计原则:
好莱坞原则:别调用我们,我们会调用你。
我们允许底层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式是”别调用我们,我们会调用你“。
在这里插入图片描述
模板方法很常见的原因是因为对创建框架来说,这个模式简直棒极了。由框架控制如何做事情,而由使用这个框架的人指定框架算法中每个步骤的细节。

用模板方法排序

在这里插入图片描述
如果要排序鸭子,就需要实现这个compareTo()方法:
在这里插入图片描述
模板方法是最常用的方法。因为模板方法提供了一种基本的方法来实现代码复用,使得子类能够指定行为。

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

9 迭代器与组合模式

在这里插入图片描述
错了,应该是:
在这里插入图片描述

一个可能的迭代器接口:
在这里插入图片描述

迭代器:
public class PancakeHouseIterator implements Iterator {ArrayList items;int position = 0;public PancakeHouseIterator(ArrayList items) {this.items = items;}public Object next() {MenuItem menuItem = items.get(position);position = position + 1;return menuItem;}public boolean hasNext() {if(position >= items.size() || items.get(position) == null) {return false;} else {return true;}}
}
菜单:
public class PancakeHouseMenu {ArrayList menuItems;// 构造器在这里//addItem在这里public Iterator createIterator() {rerurn new PancakeHouseIterator(menuItems);}//菜单的其他方法在这里
}

然后就可以快乐地使用迭代器进行打印了:
在这里插入图片描述
进一步的,将煎饼和午餐进行合并:
在这里插入图片描述

定义迭代器模式

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
在这里插入图片描述
当我们运行一个类不但要完成自己的事情(管理某种聚合),还同时要担负更多的责任(例如遍历)时,我们就给了这个类两个变化的原因。这违反了下面的设计原则。
第九个设计原则:一个类应该只有一个引起变化的原因。
在这里插入图片描述
在这里插入图片描述
如果菜单出现了树形结构,则需要使用组合模式:
组合模式允许你将对象组合成树形结构来表现”整体/部分“层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

组合模式以单一责任设计原则换取透明性。透明性:通过允许组件接口包含子管理操作和叶节点操作,客户端可以统一地处理复合对象和叶节点;因此,一个元素是复合对象还是叶节点对于客户端来说变得透明。在该模式下,可以认为叶节点是没有孩子的节点。(事实上,代码实现上也是认为没有孩子的节点是叶节点)

组合迭代器

CompositeIterator是一个不可小觑的迭代器。它的工作是遍历组件内的菜单项,而且确保所有的子菜单都被包括进来。
下面是代码,看不懂。。。特别是hasNext函数中判断iterator.hasNext。
在这里插入图片描述

import java.util.*;public class CompositeIterator implements Iterator {Stack stack = new Stack(); // 使用栈来管理迭代器public CompositeIterator(Iterator iterator) {stack.push(iterator); // 将顶层组合的迭代器压入栈中}public Object next() {if (hasNext()) { // 确保还有下一个元素Iterator iterator = (Iterator) stack.peek(); // 获取当前栈顶的迭代器MenuComponent component = (MenuComponent) iterator.next(); // 获取下一个组件if (component instanceof Menu) { // 如果是菜单,继续递归stack.push(component.createIterator()); // 将子菜单的迭代器压入栈中}return component; // 返回当前组件} else {return null; // 没有下一个元素时返回null}}public boolean hasNext() {if (stack.empty()) { // 如果栈为空,表示没有下一个元素return false;} else {Iterator iterator = (Iterator) stack.peek(); // 获取当前栈顶的迭代器if (!iterator.hasNext()) { // 如果当前迭代器没有下一个元素stack.pop(); // 弹出当前迭代器return hasNext(); // 递归检查下一个迭代器} else {return true; // 当前迭代器还有下一个元素}}}public void remove() {throw new UnsupportedOperationException(); // 不支持删除操作}
}

在这里插入图片描述
有时候,如果一个组合结构很复杂,或者遍历的代价太高,那么实现组合节点的缓存就很有帮助。

在这里插入图片描述
迭代器:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
组合模式:允许你将对象组成树形结构来表现“整体/部分”的层次结构。组合能让客户以一致的方式处理和别对象和对象组合。

10 状态模式

“策略模式和状态模式是双胞胎,在出生时才分开。”
策略模式是围绕可以互换的算法来创建成功业务的。而状态模式走的是更崇高的路,它通过改变对象内部的状态来帮助对象控制自己的行为。

在这里插入图片描述

public class SoldOutState implements State {GumballMachine gumballMachine;public SoldOutState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}public void insertQuarter() {System.out.println("You can't insert a quarter, the machine is sold out");}public void ejectQuarter() {System.out.println("You can't eject, you haven't inserted a quarter yet");}public void turnCrank() {System.out.println("You turned, but there are no gumballs");}public void dispense() {System.out.println("No gumball dispensed");}
}

定义状态模式

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
状态模式的类图:
在这里插入图片描述

在这里插入图片描述

相关文章:

《HeadFirst设计模式》笔记(上)

设计模式的目录&#xff1a; 1 设计模式介绍 要不断去学习如何利用其它开发人员的智慧与经验。学习前人的正统思想。 我们认为《Head First》的读者是一位学习者。 一些Head First的学习原则&#xff1a; 使其可视化将文字放在相关图形内部或附近&#xff0c;而不是放在底部…...

数据结构:ArrayList与顺序表

目录 &#x1f4d6;一、什么是List &#x1f4d6;二、线性表 &#x1f4d6;三、顺序表 &#x1f42c;1、display()方法 &#x1f42c;2、add(int data)方法 &#x1f42c;3、add(int pos, int data)方法 &#x1f42c;4、contains(int toFind)方法 &#x1f42c;5、inde…...

SpringBoot之核心配置

学习目标&#xff1a; 1.熟悉Spring Boot全局配置文件的使用 2.掌握Spring Boot配置文件属性值注入 3.熟悉Spring Boot自定义配置 4.掌握Profile多环境配置 5.了解随机值设置以及参数间引用 1.全局配置文件 Spring Boot使用 application.properties 或者application.yaml 的文…...

EasyExcel上传校验文件错误信息放到文件里以Base64 返回给前端

产品需求&#xff1a; 前端上传个csv 或 excel 文件&#xff0c;文件共4列&#xff0c;验证文件大小&#xff0c;类型&#xff0c;文件名长度&#xff0c;文件内容&#xff0c;如果某行某个单元格数据验证不通过&#xff0c;就把错误信息放到这行第五列&#xff0c;然后把带有…...

单片机软件定时器V4.0

单片机软件定时器V4.0 用于单片机定时执行任务等&#xff0c;比如LED GPIO等定时控制&#xff0c;内置前后台工作模式 头文件有使用例子 #ifndef __SORFTIME_APP_H #define __SORFTIME_APP_H#ifdef __cplusplus extern "C" { #endif#include <stdint.h>// #…...

超完整Docker学习记录,Docker常用命令详解

前言 关于国内拉取不到docker镜像的问题&#xff0c;可以利用Github Action将需要的镜像转存到阿里云私有仓库&#xff0c;然后再通过阿里云私有仓库去拉取就可以了。 参考项目地址&#xff1a;使用Github Action将国外的Docker镜像转存到阿里云私有仓库 一、Docker简介 Do…...

C++ 入门第26天:文件与流操作基础

往期回顾&#xff1a; C 入门第23天&#xff1a;Lambda 表达式与标准库算法入门-CSDN博客 C 入门第24天&#xff1a;C11 多线程基础-CSDN博客 C 入门第25天&#xff1a;线程池&#xff08;Thread Pool&#xff09;基础-CSDN博客 C 入门第26天&#xff1a;文件与流操作基础 前言…...

使用python将多个Excel表合并成一个表

import pandas as pd# 定义要合并的Excel文件路径和名称 file_paths [file1.xlsx, file2.xlsx, file3.xlsx, file4.xlsx, file5.xlsx]# 创建一个空的DataFrame来存储合并后的数据 merged_data pd.DataFrame()# 循环遍历每个Excel文件&#xff0c;并读取其中的数据 for file_p…...

halcon三维点云数据处理(七)find_shape_model_3d_recompute_score

目录 一、find_shape_model_3d_recompute_score例程代码二、set_object_model_3d_attrib_mod函数三、prepare_object_model_3d 函数四、create_cube_shape_model_3d函数五、获得CamPose六、project_cube_image函数七、find_shape_model_3d函数八、project_shape_model_3d函数 一…...

vue js实现时钟以及刻度效果

2025.01.08今天我学习如何用js实现时钟样式&#xff0c;效果如下&#xff1a; 一、html代码如下&#xff1a; <template><!--圆圈--><div class"notice_border"><div class"notice_position notice_name_class" v-for"item in …...

unity学习15:预制体prefab

目录 1 创建多个gameobject 2 创建prefab 2.1 创建prefab &#xff08;类&#xff09; 2.2 prefab 是一个文件 2.3 prefab可以导出 3 创建prefab variant &#xff08;子类&#xff09; 3.1 除了创建多个独立的prefab&#xff0c; 还可以创建 prefab variant 3.2 他…...

基于Thinkphp6+uniapp的陪玩陪聊软件开发方案分析

使用uni-app框架进行前端开发。uni-app是一个使用Vue.js开发所有前端应用的框架&#xff0c;支持一次编写&#xff0c;多端发布&#xff0c;包括APP、小程序、H5等。 使用Thinkphp6框架进行后端开发。Thinkphp6是一个轻量级、高性能、面向对象的PHP开发框架&#xff0c;具有易…...

MySQL - 子查询和相关子查询详解

在SQL中&#xff0c;子查询&#xff08;Subquery&#xff09;和相关子查询&#xff08;Correlated Subquery&#xff09;是非常强大且灵活的工具&#xff0c;可以用于执行复杂的数据检索和操作。它们允许我们在一个查询中嵌套另一个查询&#xff0c;从而实现更复杂的逻辑和条件…...

Android 系统签名 keytool-importkeypair

要在 Android 项目中使用系统签名并将 APK 打包时与项目一起打包&#xff0c;可以按照以下步骤操作&#xff1a; 步骤 1&#xff1a;准备系统签名文件 从 Android 系统源码中获取系统签名文件&#xff0c;通常位于 build/target/product/security 目录下&#xff0c;包括 pla…...

安卓漏洞学习(十八):Android加固基本原理

APP加固技术发展历程 APK加固整体思路 加固整体思路&#xff1a;先解压apk文件&#xff0c;取出dex文件&#xff0c;对dex文件进行加密&#xff0c;然后组合壳中的dex文件&#xff08;Android类加载机制&#xff09;&#xff0c;结合之前的apk资源&#xff08;解压apk除dex以外…...

Docker 使用Dockerfile创建镜像

创建并且生成镜像 在当前目录下创建一个名为Dockerfile文件 vi Dockerfile填入下面配置 # 使用 CentOS 作为基础镜像 FROM centos:7# 设置工作目录 WORKDIR /app# 复制项目文件到容器中 COPY bin/ /app/bin/ COPY config/ /app/config/ COPY lib/ /app/lib/ COPY plugin/ /a…...

【Python运维】利用Python实现高效的持续集成与部署(CI/CD)流程

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 持续集成与部署(CI/CD)是现代软件开发中不可或缺的实践,通过自动化测试、构建和部署流程,显著提高了开发效率与运维质量。本文详细介绍…...

成功!QT 5.15.2编译mysql驱动

首选要说明&#xff0c;5.15与6.7编译驱动是完全不同的。搞错了永远编译不出来。 参考 主要是参考安装QT&#xff0c;安装mysql等。 编译成功&#xff01;QT/6.7.2/Creator编译Windows64 MySQL驱动(MSVC版)_mingw编译qt6.7-CSDN博客 复制mysql的include和lib到一个方便的目…...

安卓NDK视觉开发——手机拍照文档边缘检测实现方法与库封装

一、项目创建 创建NDK项目有两种方式&#xff0c;一种从新创建整个项目&#xff0c;一个在创建好的项目添加NDK接口。 1.创建NDK项目 创建 一个Native C项目&#xff1a; 选择包名、API版本与算法交互的语言&#xff1a; 选择C版本&#xff1a; 创建完之后&#xff0c;可…...

第二届 Sui 游戏峰会将于 3 月 18 日在旧金山举行

3 月中旬&#xff0c;Sui 基金会和 Mysten Labs 将共同举办第二届 Sui 游戏峰会&#xff08;Sui Gaming Summit&#xff09;&#xff0c;这是一个专注于 Sui 游戏平台的 GDC 周边活动。此次峰会将与旧金山的年度游戏开发者大会&#xff08;GDC&#xff0c;Game Developers Conf…...

CentOS 7如何编译安装升级gcc至7.5版本?

CentOS 7如何编译安装升级gcc版本? 由于配置CentOS-SCLo-scl.repo与CentOS-SCLo-scl-rh.repo后执行yum install -y devtoolset-7安装总是异常&#xff0c;遂决定编译安装gcc7.5 # 备份之前的yum .repo文件至 /tmp/repo_bak 目录 mkdir -p /tmp/repo_bak && cd /etc…...

前端面试五之vue2基础

1.属性绑定v-bind&#xff08;&#xff1a;&#xff09; v-bind 是 Vue 2 中用于动态绑定属性的核心指令&#xff0c;它支持多种语法和用法&#xff0c;能够灵活地绑定 DOM 属性、组件 prop&#xff0c;甚至动态属性名。通过 v-bind&#xff0c;可以实现数据与视图之间的高效同…...

“组件、路由懒加载”,在 Vue3 和 React 中分别如何实现? (copy)

Vue3 和 React 组件懒加载实现方式 React 中组件懒加载的实现方式 React 提供了 React.lazy 和 Suspense 两个 API 来实现组件的懒加载。React.lazy 用于动态导入组件&#xff0c;而 Suspense 则用于指定加载过程中的占位内容。例如&#xff0c;可以通过以下代码实现懒加载&a…...

CSS 选择器全解析:分组选择器/嵌套选择器,从基础到高级

一、CSS 选择器基础&#xff1a;从单个元素到多个元素 CSS 选择器是用来定位 HTML 元素的工具&#xff0c;就像 “元素的地址”。最基础的选择器有&#xff1a; 元素选择器&#xff08;按标签名定位&#xff09; css p { color: red; } /* 所有<p>标签 */ div { b…...

跳转指令四维全解:从【call/jmp 】的时空法则到内存迷宫导航术

一、核心概念&#xff1a;代码世界的空间定位法则 在汇编世界里&#xff0c;我们可以把内存想象成一栋巨大的图书馆&#xff1a; CS&#xff08;代码段寄存器&#xff09; 楼层编号 IP&#xff08;指令指针&#xff09; 房间编号 当前执行位置 CS:IP&#xff08;如3楼201…...

Model Context Protocol (MCP) 是一个前沿框架

微软发布了 Model Context Protocol (MCP) 课程&#xff1a;mcp-for-beginners。 Model Context Protocol (MCP) 是一个前沿框架&#xff0c;涵盖 C#、Java、JavaScript、TypeScript 和 Python 等主流编程语言&#xff0c;规范 AI 模型与客户端应用之间的交互。 MCP 课程结构 …...

Go字符串切片操作详解:str1[:index]

在Go语言中&#xff0c;return str1[:index] 是一个​​字符串切片操作​​&#xff0c;它截取字符串的一部分。让我们深入解析这个操作的含义和原理&#xff1a; 基本语法和含义 str1&#xff1a;原始字符串[:index]&#xff1a;切片操作符str1[:index]&#xff1a; ​​起始…...

【办公类-104-01】20250606通义万相50分一天用完,通义万相2.1专业版测试

背景需求&#xff1a; 昨天打开通义万相&#xff0c;发现分数降低到3位数&#xff0c;原来时1500.仔细看&#xff0c;原来每天的50分&#xff0c;只有1天有效期了。 用掉试试&#xff0c;用的是之前的30天积分&#xff0c;还是今天的1天积分 纯白色背景&#xff0c;卡通简笔画…...

极速互联·智控未来——SG-Can(FD)Hub-600 六通道CANFD集线器

工业通信的全维进化&#xff0c;CANFD高速网络的终极枢纽&#xff01; 核心革新 CANFD协议深度支持&#xff1a;名义波特率5K-1Mbps&#xff0c;数据域速率飙升至5Mbps&#xff08;较传统CAN提升5倍&#xff09;&#xff0c;开启位速率转换最低100Kbps&#xff0c;完美兼容新旧…...

ajax学习手册

Ajax 通俗易懂学习手册 目录 Ajax 基础概念XMLHttpRequest 详解Fetch API (现代方式)处理不同数据格式错误处理和状态码Ajax 高级技巧实战项目案例最佳实践 Ajax 基础概念 什么是 Ajax&#xff1f; Ajax Asynchronous JavaScript And XML 通俗解释&#xff1a; Ajax 就像…...