【设计模式】- 创建者模式

单例模型

饿汉式

静态方法创建对象

public class Singleton {// 私有构造方法private Singleton(){}private static Singleton instance = new Singleton();// 提供一个外界获取的方法public static Singleton getInstance(){return instance;}
}

静态代码块创建对象

public class Singleton {private Singleton(){}private static Singleton instance;static {instance = new Singleton();}public static Singleton getInstance(){return instance;}
}

懒汉式

synchronized关键字

public class Singleton {private Singleton(){}private static Singleton instance;public static Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}
}

问题】上边的代码是存在线程不安全的情况的,当线程1进来,判读instance==null成立,准备创建对象;但是线程1还没创建对象完毕时,线程2来了,线程2也判断成立,也去创建对象,此时就会创建两个不同的对象。
解决】:给getInstance方法上添加synchronized关键字

public class Singleton {private Singleton(){}private static Singleton instance;public static synchronized Singleton getInstance(){if(instance == null){instance = new Singleton(); // 下边简称:“写操作”}return instance; // 下边简称:“读操作”}
}

双重检查锁

问题】:对于getInstance()方法,其实大部分的操作都是读操作,读操作是线程安全的,如果直接给getInstance方法上加锁,其实会造成大量的线程等待。
解决】:调整加锁的时机,双重检查锁

public class Singleton {private Singleton(){}private static volatile Singleton instance; // volatile:保证指令的有序性和可见性public static Singleton getInstance(){// 第一次判断,如果instance的值不为null,不需要抢占锁,直接返回对象if(instance == null){synchronized (Singleton.class){// 第二次判断if(instance == null){instance = new Singleton();}}}return instance;}
}

静态内部类

public class Singleton {private Singleton(){}// 定义一个静态内部类private static class SingletonHolder{// 在内部类中声明并初始化外部类的对象private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){return SingletonHolder.INSTANCE;}
}

JVM加载外部类的过程是不会加载静态内部类的,只有内部类的属性、方法被调用时才会加载并初始化静态属性。静态属性被static修饰,所以只会被实例化一次。

枚举类

枚举类也是线程安全的,只会被加载一次,也是所有单例实现中唯一一种不会被破坏的单例模式

public enum Singleton {INSTANCE
}

枚举方式是属于饿汉式的方式,在不考虑浪费内存空间的情况下,首选枚举方式

存在的问题

问题】:破坏单例模式(让单例模式可以创建多个对象,枚举方式除外)

通过序列化和反序列化破坏单例模式

public class Client {public static void main(String[] args) throws Exception {writeObject2File();readObjectFromFile(); // Singleton@27bc2616readObjectFromFile(); // Singleton@3941a79c}// 从文件中读取对象private static void readObjectFromFile() throws Exception {// 1. 创建输入流对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Desktop\\a.txt"));// 2. 读取对象Singleton instance = (Singleton) ois.readObject();System.out.println(instance);// 3. 释放资源ois.close();}// 从文件中写对象public static void writeObject2File() throws Exception {// 1. 获取Singleton对象Singleton instance = Singleton.getInstance();// 2. 将对象写入文件ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\Desktop\\a.txt"));oos.writeObject(instance);// 3. 释放资源oos.close();}
}

上面的代码生成的两个对象不是同一个对象,破坏了单例模式

通过反射破坏单例模式

public class Client {public static void main(String[] args) throws Exception {// 1. 获取Singleton的字节码对象Class clazz = Singleton.class;// 2. 获取无参构造方法对象Constructor cons = clazz.getDeclaredConstructor();// 3. 取消访问检查(暴力反射)cons.setAccessible(true);// 4. 创建对象Singleton s1 = (Singleton) cons.newInstance();Singleton s2 = (Singleton) cons.newInstance();System.out.println(s1 == s2); // false - 破坏单例模式}
}

上边代码返回的是false,说明s1和s2不是同一个对象,破坏了单例模式

问题解决

序列化、反序列化破坏单例模式解决方法

在Singleton类种添加readResolve()方法,在反序列化时被反射调用。如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回new出来的对象。

public class Singleton implements Serializable {private Singleton(){}// 定义一个静态内部类private static class SingletonHolder{// 在内部类中声明并初始化外部类的对象private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){return SingletonHolder.INSTANCE;}// 当进行反序列化时,自动调用该方法,将该方法的返回值直接返回public Object readResolve(){return SingletonHolder.INSTANCE;}
}

反射方式破坏单例模式解决方法

其实反射破坏的原理是:通过反射获取Singleton的私有构造方法,然后通过这个私有的构造方法去创建对象。
因此我们只需要在构造方法里添加一个判断即可

public class Singleton implements Serializable {private static boolean flag = false;private Singleton(){synchronized (Singleton.class){if(flag) {throw new RuntimeException("不能创建多个对象");}flag = true;}}// 定义一个静态内部类private static class SingletonHolder{// 在内部类中声明并初始化外部类的对象private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){return SingletonHolder.INSTANCE;}
}

JDK源码解析 - Runtime类

饿汉式:
在这里插入图片描述

工厂模式

引例:点咖啡

现在有美式咖啡、拿铁咖啡,顾客可以选择咖啡的种类,咖啡都需要进行加糖加奶。

原本的写法:

咖啡类:

public abstract class Coffee {public abstract String getName();// 加糖public void addsugar() {System.out.println("加糖");}// 加奶public void addmilk() {System.out.println("加奶");}
}

美式咖啡:

public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}
}

拿铁咖啡:

public class LatteCoffee extends Coffee {@Overridepublic String getName() {return "拿铁咖啡";}
}

咖啡店:

public class CoffeeStore {public Coffee orderCoffee(String coffeeType) {// 声明Coffee类型的变量,根据不同的类型创建不同的子类对象Coffee coffee = null;if("american".equals(coffeeType)) {coffee = new AmericanCoffee();}else if("latte".equals(coffeeType)) {coffee = new LatteCoffee();}else {throw new RuntimeException("对不起的,您所点的咖啡没有");}// 加配料coffee.addmilk();coffee.addsugar();return coffee;}
}

测试方法:

public class Client {public static void main(String[] args) {// 创建咖啡店类CoffeeStore store = new CoffeeStore();// 点咖啡Coffee coffee = store.orderCoffee("latte");System.out.println(coffee.getName());}
}

存在问题】:如果需要更换对象,那么所有new对象的地方都要修改一遍,这就违背了软件设计的开闭原则。
解决】:工厂模式

简单工厂模式

角色:

  • 抽象产品:定义了产品的规范(咖啡类)
  • 具体产品:是现货集成抽象产品的子类(美式咖啡、拿铁咖啡)
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品

简单咖啡工厂类,用来生产咖啡:

public class SimpleCoffeeFactory {public Coffee createCoffee(String coffeeType) {// 声明Coffee类型的变量,根据不同的类型创建不同的子类对象Coffee coffee = null;if("american".equals(coffeeType)) {coffee = new AmericanCoffee();}else if("latte".equals(coffeeType)) {coffee = new LatteCoffee();}else {throw new RuntimeException("对不起的,您所点的咖啡没有");}return coffee;}
}

咖啡店:

public class CoffeeStore {public Coffee orderCoffee(String coffeeType) {SimpleCoffeeFactory factory = new SimpleCoffeeFactory();// 调用生产咖啡的方法Coffee coffee = factory.createCoffee(coffeeType);// 加配料coffee.addmilk();coffee.addsugar();return coffee;}
}

解除了CoffeeStore和具体的咖啡的耦合
优势】:工厂类的客户端可能有很多,这样只需要去修改SimpleCoffeeFactory的代码,可以省去其他的修改操作。
劣势】:如果要再加新的品种的咖啡,就必须要修改SimpleCoffeeFactory的代码,这违反了开闭原则。

工厂方法模式

角色:

  • 抽象产品:定义了产品的规范(咖啡类)
  • 具体产品:是现货集成抽象产品的子类(美式咖啡、拿铁咖啡)
  • 抽象工厂:提供创建产品的接口,调用者通过访问它具体工厂的工厂方法来创建产品
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品

抽象工厂:

public interface CoffeeFactory {// 创建咖啡对象的方法Coffee createCoffee();
}

具体工厂:

  • 拿铁咖啡工厂对象 - 用来生产拿铁咖啡
public class LatteCoffeeFactory implements CoffeeFactory {@Overridepublic Coffee createCoffee() {return new LatteCoffee();}
}
  • 美式咖啡工厂对象 - 用来生产美式咖啡
public class AmericanCoffeeFactory implements CoffeeFactory {@Overridepublic Coffee createCoffee() {return new AmericanCoffee();}
}

咖啡店:

public class CoffeeStore {private CoffeeFactory factory;public void setFactory(CoffeeFactory factory) {this.factory = factory;}// 点咖啡public Coffee orderCoffee() {// 创建咖啡Coffee coffee = factory.createCoffee();// 加配料coffee.addmilk();coffee.addmilk();return coffee;}
}

测试方法:

public class Client {public static void main(String[] args) {// 创建咖啡店类CoffeeStore store = new CoffeeStore();store.setFactory(new AmericanCoffeeFactory()); // 生产美式咖啡// 点咖啡Coffee coffee = store.orderCoffee();System.out.println(coffee.getName());}
}

优势】:用户只要知道具体工程的类名就可以得到产品;系统增加新的产品只需要新增具体产品类和对应的具体工厂类即可。
劣势】:每增加一个产品就需要增加一个具体产品类和具体工厂类, 增加了系统的复杂度

抽象工厂模式

抽象工厂模式和工厂方法模式的区别:

  • 工厂方法模式:只生产一个等级的产品
  • 抽象工厂模式:可以创建多个不同等级的产品

需求变更】:现在咖啡店不仅需要生产咖啡,还需要生产甜品

甜品抽象类:

public abstract class Dessert {abstract void show();
}

提拉米苏类:

public class Trimisu extends Dessert{@Overridevoid show() {System.out.println("提拉米苏");}
}

抹茶慕斯类:

public class MatchaMousse extends Dessert{@Overridevoid show() {System.out.println("抹茶慕斯");}
}

甜品抽象工厂:

public interface DessertFactory {// 生产咖啡的功能Coffee createCoffee();// 生产甜品的功能Dessert createDessert();
}

意大利风味甜品工厂(生产拿铁咖啡和提拉米苏甜品):

public class ItaltyDessertFactory implements DessertFactory{ // 意大利风味甜品工厂(生产拿铁咖啡和提拉米苏甜品)@Overridepublic Coffee createCoffee() {return new LatteCoffee(); // 拿铁咖啡}@Overridepublic Dessert createDessert() {return new Trimisu(); // 提拉米苏}
}

美式咖啡的甜品工厂(生产美式咖啡和抹茶慕斯):

public class AmericanDessertFactory implements DessertFactory{ // 美式咖啡的甜品工厂 - 生产美式咖啡和抹茶慕斯@Overridepublic Coffee createCoffee() {return new AmericanCoffee(); // 美式咖啡}@Overridepublic Dessert createDessert() {return new MatchaMousse(); // 抹茶慕斯}
}

测试类:

public class Client {public static void main(String[] args) {// 创建意大利风味的工厂ItaltyDessertFactory it = new ItaltyDessertFactory();Coffee coffee = it.createCoffee(); // 拿铁咖啡Dessert dessert = it.createDessert(); // 提拉米苏System.out.println(coffee.getName());dessert.show();}
}

如果要加一个产品族,只需要再加一个对应的工厂类,不需要修改其他类
优点】:客户端只能使用同一个产品族中的对象
缺点】:产品族种需要新增一个新的产品,所有的工厂类都需要进行修改。

适用场景:

  • 需要创建的对象是一系列相互关联或相互依赖的产品族(电器工厂中的电视机、洗衣机、空调)
  • 系统种有多个产品族每次只用其中一种产品(有人只喜欢穿一个品牌的衣服和裤子)
  • 系统提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构
  • 如:搜狗输入法换皮肤(一套一起换)

模式扩展(Spring框架底层)

bean.properties文件:

american = com.itheima.pattern02factory.factory_04_config.AmericanCoffee
latte = com.itheima.pattern02factory.factory_04_config.LatteCoffee

工厂类:

public class CoffeeFactory {// 1. 定义容器对象存储咖啡对象private static HashMap<String, Coffee> map = new HashMap<>();// 2. 加载配置文件,并创建该配置文件里类的对象并进行存储(只需要加载一次)static {// 2.1 创建Properties对象Properties p = new Properties();// 2.2 调用p对象中的load方法进行配置文件的加载InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");try {p.load(is);// 2.3 从p集合中获取全类名并创建对象Set<Object> keys = p.keySet();for (Object key : keys) {String className = p.getProperty((String) key);// 2.4 通过反射技术创建对象Class clazz = Class.forName(className);Coffee coffee = (Coffee) clazz.newInstance();// 2.5 将名称和对象存储到容器中map.put((String) key, coffee);}} catch (Exception e) {throw new RuntimeException(e);}}// 根据名称获取对象public static Coffee createCoffee(String name) {return map.get(name);}
}

JDK源码解析 - Collection.iterator()

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

Collection是抽象工厂;ArrayList是具体工厂
【补】:DateForamt类中的getInstance()、Calendar类中的getInstance()也是工厂模式

原型模式

用一个已经创建的对象作为原型,复制这个原型对象来创建一个和原型对象相同的新对象。

包含的角色:

  • 抽象原型类:规定了具体原型对象必须实现的clone()方法
  • 具体原型类:实现抽象原型类中的clone()方法,他是可以被复制的对象

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同。对于非基本类型属性,克隆对象和源对象指向的是同一块内存空间
深克隆:创建一个新对象,属性中的引用的其他对象也会被克隆,不会指向原有对象地址。

引例1:克隆对象

具体原型对象

public class Relizetype implements Cloneable { // 必须实现Cloneable接口:否则调用clone()会抛出CloneNotSupportedExceptionpublic Relizetype() {System.out.println("具体的原型类创建成功");}@Overridepublic Relizetype clone() throws CloneNotSupportedException { // clone()方法是在Object类里的System.out.println("具体原型复制成功");return (Relizetype) super.clone();}
}

测试类

public class Client {public static void main(String[] args) throws CloneNotSupportedException {// 创建原型对象Relizetype relizetype = new Relizetype();// 调用原型类中的clone()方法进行对象的克隆Relizetype clone = relizetype.clone();System.out.println(relizetype == clone); // false}
}

必须实现Cloneable接口:否则调用clone()会抛出CloneNotSupportedException。
重写clone()方法:通常需将其改为public访问权限,并返回具体类型。
clone() 方法创建了一个新的对象,而不是返回原对象的引用,因为java的Object.clone()方法是一个native方法,不会调用构造方法,而是直接分配内存并复制数据

引例2.1:三好学生奖状分发(浅克隆)

奖状类:

@Data
public class Citation implements Cloneable {// 三好学生上的姓名private String name;@Overridepublic Citation clone() throws CloneNotSupportedException {return (Citation) super.clone();}public void show() {System.out.println(name + "同学被评为三好学生");}
}

测试类:

public class CitationTest {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建原型对象Citation citation = new Citation();// 2. 克隆奖状对象Citation citation1 = citation.clone();citation.setName("张三");citation1.setName("李四");citation.show(); // 张三同学被评为三好学生citation1.show(); // 李四同学被评为三好学生}
}

使用场景

  1. 对象的创建非常复杂,可以使用原型模式快捷创建对象(原型对象的所属类必须实现clone()方法)
  2. 性能和安全的要求比较高

引例2.2:三好学生奖状分发(深克隆)

学生类:

@Data
@Accessors(chain = true)
public class Student {// 学生姓名private String name;
}

奖状类:

@Data
public class Citation implements Cloneable {private Student student;@Overridepublic Citation clone() throws CloneNotSupportedException {return (Citation) super.clone();}public void show() {System.out.println(student.getName() + "同学被评为三好学生");}
}

测试类:

public class CitationTest {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建原型对象Citation citation = new Citation();Student stu = new Student().setName("张三");citation.setStudent(stu);// 2. 克隆奖状对象Citation citation1 = citation.clone();Student stu1 = citation1.getStudent();stu1.setName("李四");citation.show(); // 李四同学被评为三好学生citation1.show(); // 李四同学被评为三好学生}
}

问题】由上边测试结果可知,修改了citation1成员变量的值的同时,也修改了citation对象的值
产生原因】这是因为stu和stu1此时是一个对象(这就是浅克隆),此时将stu1的属性改成“李四”,导致stu的属性也变成“李四”

修改】:把浅克隆变成深克隆(使用序列化和反序列化实现)

public class CitationTest1 {public static void main(String[] args) throws Exception {// 1. 创建原型对象Citation citation = new Citation();Student stu = new Student().setName("张三");citation.setStudent(stu);// 把对象写入文件中ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); // 对象输出流对象oos.writeObject(citation); // 写对象oos.close(); // 释放资源// 从文件中读取对象 (2. 克隆奖状对象)ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));Citation citation1 = (Citation) ois.readObject();citation1.getStudent().setName("李四");ois.close();citation.show(); // 张三同学被评为三好学生citation1.show(); // 李四同学被评为三好学生}
}

Citation类和Student类都必须实现Serializable接口,否则会抛NotSerializableException异常

修改】:把浅克隆变成深克隆(在重写clone()方法的时候调用属性的clone()方法)

奖状类:

@Data
public class Citation implements Cloneable, Serializable {private Student student;@Overridepublic Citation clone() throws CloneNotSupportedException {Citation clone = (Citation) super.clone();clone.setStudent(student.clone()); // 深拷贝return clone;}public void show() {System.out.println(student.getName() + "同学被评为三好学生");}
}

学生类:

@Data
@Accessors(chain = true)
public class Student implements Serializable, Cloneable {// 学生姓名private String name;@Overridepublic Student clone() throws CloneNotSupportedException {return (Student) super.clone();}
}

测试类:

public class CitationTest {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建原型对象Citation citation = new Citation();Student stu = new Student().setName("张三");citation.setStudent(stu);// 2. 克隆奖状对象Citation citation1 = citation.clone();citation1.getStudent().setName("李四");citation.show(); // 张三同学被评为三好学生citation1.show(); // 李四同学被评为三好学生}
}

建造者模式

将复杂对象的构建和表示分离,使同样的构建过程可以创建不同的表示。

建造者建造的产品一般需要有较多的共同点,组成部分需要相似(如果产品之间差异比较大,不适合使用建造者模式)

  • 产品类(Product):要创建的复杂对象
  • 抽象建造者类(Builder):这个接口规定要实现复杂对象那部分的创建,不涉及具体的对象创建
  • 具体建造者类(ConcreteBuilder):实现Builder接口,完成复杂产品的各个部件的具体创建方法(强调装配的过程)
  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,不涉及具体产品信息,只保证对象各个部分完整创建或按照某种顺序创建
    在这里插入图片描述

引例:创建共享单车

需求】:自行车包含了车架、车座等组件的生产;车架又有碳纤维,铝合金等材质;车座有橡胶、真皮的材质
在这里插入图片描述

Bike类:产品类(车架、车座组件)
Builder:抽象建造者(MobikeBuilder、OfoBuilder是具体的建造者)
Director:指挥者

产品类:

@Data
public class Bike {/*车架*/private String frame;/*车座*/private String seat;
}

抽象构建者:

public abstract class Builder {/*Bike对象*/protected Bike bike = new Bike(); // 目前还没有组装组件(指挥者做)/*构建车架*/public abstract void buildFrame();/*构建车座*/public abstract void buildSeat();/*构建自行车*/public abstract Bike createBike();
}

具体构建者1(摩拜单车):

public class MobileBuilder extends Builder{@Overridepublic void buildFrame() {bike.setFrame("碳纤维车架");}@Overridepublic void buildSeat() {bike.setSeat("真皮车座");}@Overridepublic Bike createBike() {return bike;}
}

具体构建者2(ofo单车):

public class OfoBuilder extends Builder{@Overridepublic void buildFrame() {bike.setFrame("铝合金车架");}@Overridepublic void buildSeat() {bike.setSeat("橡胶车座");}@Overridepublic Bike createBike() {return bike;}
}

指挥者类:

public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}/*组装自行车*/public Bike construct() {builder.buildFrame();builder.buildSeat();return builder.createBike();}
}

测试类:

public class Client {public static void main(String[] args) {// 1. 创建指挥者对象Director director = new Director(new MobileBuilder());// 2. 让指挥者进行自行车的组装Bike bike = director.construct();System.out.println(bike.getFrame());System.out.println(bike.getSeat());}
}

Director指挥者类在建造者模式中很重要,是由指挥者类来指导具体的建造者应该如何构建产品,控制调用的先后顺序,向调用者返回完整的产品类。

改进】:指挥者类也可以和抽象建造者进行结合:

public abstract class Builder {/*Bike对象*/protected Bike bike = new Bike(); // 目前还没有组装组件(指挥者做)/*构建车架*/public abstract void buildFrame();/*构建车座*/public abstract void buildSeat();/*构建自行车*/public abstract Bike createBike();/*组装自行车*/public Bike construct() {this.buildFrame();this.buildSeat();return this.createBike();}
}

这样做虽然可以不用写指挥者类,但是也加重了建造者类的职责,也不符合单一职责原则,如果construct()过于复杂,还是建议封装到Director中。

模式扩展

当一个类的构造方法需要传入很多参数,如果创建这个类的实例,代码的可读性就会很差,就可以使用建造者模式进行重构。
手机类:

@Data
public class Phone {private String cpu;private String screen;private String memory;private String mainboard;/*私有构造方法*/private Phone(Builder builder) {this.cpu = builder.cpu;this.screen = builder.screen;this.memory = builder.memory;this.mainboard = builder.mainboard;}public static final class Builder {private String cpu;private String screen;private String memory;private String mainboard;public Builder cpu(String cpu) {this.cpu = cpu;return this; // 为了链式编程}public Builder screen(String screen) {this.screen = screen;return this;}public Builder memory(String memory) {this.memory = memory;return this;}public Builder mainboard(String mainboard) {this.mainboard = mainboard;return this;}/*使用构建者创建Phone对象*/public Phone build() {return new Phone(this);}}
}

测试类:

public class Client {public static void main(String[] args) {/*创建手机对象 - 通过构建者对象获取手机对象*/Phone phone = new Phone.Builder().cpu("intel").screen("三星").memory("金士顿内存条").mainboard("华硕").build();System.out.println(phone); // Phone(cpu=intel, screen=三星, memory=金士顿内存条, mainboard=华硕)}
}

将构建的顺序交给客户,这个相当于lombok里的@Builder注解

构建者模式对比

工厂方法模式 vs 建造者模式

  1. 工厂方法模式:整体对象的创建方式
  2. 建造者模式:部件构建的过程

抽象工厂模式 vs 建造者模式

  1. 抽象工厂模式:实现对产品家族的创建,不需要关心建造过程,只关心什么产品由什么工厂生产
  2. 建造者模式:按照指定的蓝图建造产品,通过组装零件而产生一个新产品

抽象工厂模式:汽车配件生产工厂(生产一个产品族的产品)
建造者模式:骑车组装工厂(通过对配件的组装可以返回一个完整的骑车)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81527.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

逻辑与非逻辑的弥聚

非逻辑弥聚与逻辑弥聚是复杂系统中两种不同的信息整合方式。逻辑弥聚侧重于通过明确的规则、规律和结构化方法&#xff0c;将分散的信息或功能进行有序的组织和集中处理&#xff0c;强调理性和确定性。而非逻辑弥聚则更多地涉及情感、直觉、经验等非线性、非结构化的因素&#…

Linux进程信号(三)之信号产生2

文章目录 4. 由软件条件产生信号5. 硬件异常产生信号模拟一下除0错误和野指针异常除0错误野指针错误 总结思考一下 4. 由软件条件产生信号 SIGPIPE是一种由软件条件产生的信号,在“管道”中已经介绍过了。 软件条件不就绪&#xff0c;很明显这个软件条件没有直接报错&#xff…

读取18B20的问题,时钟太慢了

使用MSP430&#xff0c;1M时钟&#xff0c;在读取18B20数据时&#xff0c;一直存在问题&#xff0c;使用逻辑分析仪读取的数据也是莫名其妙&#xff0c;查看电路图和器件也没有发现问题&#xff0c;就这样断断续续的卡了一周多。 今天忽然想把时钟升一下试试&#xff0c;原来1…

第12章 Java多线程机制

12.1 进程与线程 4种状态&#xff1a;新建、运行、中断和死亡。 &#xff08;新建、运行、中断和死亡&#xff09; 建立线程的两种方法&#xff1a;用Thread类或其子类。 线程新建后&#xff0c;必须调用 start () 方法使其进入就绪队列&#xff0c;才有机会获得 CPU 资源&a…

利用 Amazon Bedrock Data Automation(BDA)对视频数据进行自动化处理与检索

当前点播视频平台搜索功能主要是基于视频标题的关键字检索。对于点播平台而言&#xff0c;我们希望可以通过优化视频搜索体验满足用户通过模糊描述查找视频的需求&#xff0c;从而提高用户的搜索体验。借助 Amazon Bedrock Data Automation&#xff08;BDA&#xff09;技术&…

React 19版本refs也支持清理函数了。

文章目录 前言一、refs 支持清理函数二、案例演示1.useEffect写法2.React 19改进 的ref写法 总结 前言 React 19版本发布了ref支持清理函数了&#xff0c;这样就可以达到useEffect一样的效果了。为啥需要清理函数呢&#xff0c;这是因为节约内存。 清理事件监听&#xff08;避…

城市内涝监测预警系统守护城市安全

一、系统背景 城市内涝是指由于强降水或连续性降水超过城市排水能力&#xff0c;导致城市内产生积水灾害的现象。随着气候变化和城市化进程的加快&#xff0c;城市内涝现象愈发频繁和严重。传统的城市排水系统已难以满足当前的城市排水需求&#xff0c;特别是在暴雨等极端天气条…

Flink 作业提交流程

Apache Flink 的 作业提交流程&#xff08;Job Submission Process&#xff09; 是指从用户编写完 Flink 应用程序&#xff0c;到最终在 Flink 集群上运行并执行任务的整个过程。它涉及多个组件之间的交互&#xff0c;包括客户端、JobManager、TaskManager 和 ResourceManager。…

ctr查看镜像

# 拉取镜像到 k8s.io 命名空间 sudo nerdctl --namespace k8s.io pull nginx:1.23.4 # 验证镜像是否已下载 sudo nerdctl --namespace k8s.io images 下载镜像到k8s.io名称空间下 nerdctl --namespace k8s.io pull zookeeper:3.6.2 sudo ctr image pull --namespace k8s.io …

中科院自动化研究所通用空中任务无人机!基于大模型的通用任务执行与自主飞行

作者&#xff1a; Ji Zhao and Xiao Lin 单位&#xff1a;中科院自动化研究所 论文标题&#xff1a;General-Purpose Aerial Intelligent Agents Empowered by Large Language Models 论文链接&#xff1a;https://arxiv.org/pdf/2503.08302 主要贡献 硬件-软件协同设计框…

数据结构 -- 树形查找(三)红黑树

红黑树 为什么要发明红黑树 平衡二叉树AVL&#xff1a;插入/删除很容易破坏平衡性&#xff0c;需要频繁调整树的形态。如&#xff1a;插入操作导致不平衡&#xff0c;则需要先计算平衡因子&#xff0c;找到最小不平衡子树&#xff08;时间开销大&#xff09;&#xff0c;在进行…

容器化-k8s-使用和部署

一、K8s 使用 1、基本概念 集群: 由 master 节点和多个 slaver 节点组成,是 K8s 的运行基础。节点: 可以是物理机或虚拟机,是 K8s 集群的工作单元,运行容器化应用。Pod: K8s 中最小的部署单元,一个 Pod 可以包含一个或多个紧密相关的容器,这些容器共享网络和存储资源。…

力扣-283-移动零

1.题目描述 2.题目链接 283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 3.题目代码 class Solution {public void moveZeroes(int[] nums) {int dest-1;int cur0;while(cur<nums.length){if(nums[cur]0){cur;}else if(nums[cur]!0){swap(nums,cur,dest1);cur;dest…

前端开发笔记与实践

一、Vue 开发规范与响应式机制 1. 组件命名规范 自定义组件使用大驼峰命名法&#xff08;如 MyComponent&#xff09;&#xff0c;符合 Vue 官方推荐&#xff0c;便于与原生 HTML 元素区分。 2. Proxy vs defineProperty 特性Proxy&#xff08;Vue3&#xff09;Object.defi…

如何给PSCAD添加库文件

1、点击Options 2、选择蓝色的选项 3、查看Intel(R) Visual Fortran Compiler XE 的版本 4、打开原文件的Library 5、打开 6、点击这个文件的右键 7、然后选择第一项project setting 9、先把第8步中link里面原有的路径删除&#xff0c;再点browes[A1] &#xff0c;然后选择 [A…

milvus+flask山寨《从零构建向量数据库》第7章case2

继续流水账完这本书&#xff0c;这个案例是打造文字形式的个人知识库雏形。 create_context_db: # Milvus Setup Arguments COLLECTION_NAME text_content_search DIMENSION 2048 MILVUS_HOST "localhost" MILVUS_PORT "19530"# Inference Arguments…

【第一篇】 创建SpringBoot工程的四种方式

简介&#xff1a; 通过此篇博客你可以使用任何方式进行创建 SpringBoot 项目&#xff0c;并且在文章的最后附上答疑解惑一节&#xff0c;为你排除在使用过程中发生的常见问题。文章内容若存在错误或需改进的地方&#xff0c;欢迎大家指正&#xff01;若对操作有任何疑问欢迎留言…

GPT( Generative Pre-trained Transformer )模型:基于Transformer

GPT是由openAI开发的一款基于Transformer架构的预训练语言模型&#xff0c;拥有强大的生成能力和多任务处理能力&#xff0c;推动了自然语言处理&#xff08;NLP&#xff09;的快速发展。 一 GPT发展历程 1.1 GPT-1&#xff08;2018年&#xff09; 是首个基于Transformer架构…

网络检测工具InternetTest v8.9.1.2504 单文件版,支持一键查询IP/DNS、WIFI密码信息

—————【下 载 地 址】——————— 【​本章下载一】&#xff1a;https://drive.uc.cn/s/295e068b79314 【​本章下载二】&#xff1a;https://pan.xunlei.com/s/VOQDXguH0DYPxrql5y2zlkhTA1?pwdg2nx# 【百款黑科技】&#xff1a;https://ucnygalh6wle.feishu.cn/wiki/…

CSS- 4.1 浮动(Float)

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在HBuilder中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 HTML系列文章 已经收录在前端专栏&#xff0c;有需要的宝宝们可以点击前端专栏查看&#xff01; 点…