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

软件构造 | Design Patterns for Reuse and Maintainability

Design Patterns for Reuse and Maintainability

(面向可复用性和可维护性的设计模式)

Open-Closed Principle (OCP) ——对扩展的开放,对修改已有代码的封

Why reusable design patterns

A design…

  1. …enables flexibility to change (reusability)
  2. …minimizes the introduction of new problems when fixing old ones (maintainability)
  3. …allows the delivery of more functionality after an initial delivery (extensibility).

除了类本身,设计模式更强调多 个类/对象之间的关系和交互过程—比接口/类复用的粒度更大.

1 🍉Creational patterns

Factory Method pattern(工厂方法)

Also known as “Virtual Constructor”(虚拟构造器)

  1. 当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体 创建的实例时,用工厂方法。
  2. 定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个 类的实例化延迟到其子类。

在这里插入图片描述

// Abstract product
public interface Trace{// turn om and off debuggingpublic void setDebug(boolean debug);// write out aa debug messagepublic void debug(String message);// write out an error messagepublic void error(String message);
}// Concrete product 1
public class FileTrace implements Trace{...}// Concrete product 1
public class  SystemTrace implements Trace{...}

工厂方法来创建实例

interface TraceFactory {public Trace getTrace();public Trace getTrace(String type);void otherOperation(){};
}public class Factory1 implements TraceFactory {public Trace getTrace() {return new SystemTrace();}
}// 根据类型决定创建哪个具体产品
public class Factory2 implements TraceFactory {public getTrace(String type) {    // public static getTrace(String type);if(type.equals(“file”)return new FileTrace();else if (type.equals(“system”)return new SystemTrace();}
}Trace log1 = new Factory1().getTrace(); //  TraceFactory2.getTrace(“system”)
log1.setDebug(true);
log1.debug( "entering log" );
Trace log2 = new Factory2().getTrace("system");
log2.setDebug(false);
log2.debug("...");

2 🍈Structural patterns

2.1 Adapter适配器模式

Convert the interface of a class into another interface that clients expect to get.

将某个类/接口转换为client期望的其他形式

A LegacyRectangle 组件的 display() 方法希望接收 接收 "x、y、w、h "参数。但客户希望传递 "左上方 x 和 y "以及 "右下方 ”x 和 y”。这种不协调可以通过添加额外的间接层(即适配器对象)来解决。

在这里插入图片描述

没有适配器

在这里插入图片描述

有适配器

在这里插入图片描述

2.2 Decorator(装饰器模式)

对每一个特性构造子类,通过委派机制增加到对象上

在这里插入图片描述

继承与装饰器的区别

  1. 目的:继承主要用于实现代码重用和扩展功能,而装饰器主要用于在不修改原有类代码的情况下动态地添加新功能或修改其行为。
  2. 耦合性:继承可能导致较高的耦合性,因为子类与父类紧密相关;而装饰器与原始类之间的耦合度较低,因为它们之间是通过接口或抽象类进行交互的。
  3. 灵活性:装饰器比继承更灵活,因为它们可以在运行时动态地添加或删除功能,而不需要修改原始类的代码。
  4. 扩展性:虽然继承也支持扩展功能,但装饰器提供了一种更灵活、更可维护的方式来扩展类的功能。
  5. 使用场景:当需要在多个类之间共享一些公共功能时,可以使用继承;当需要在不修改原始类代码的情况下动态地添加新功能或修改其行为时,可以使用装饰器。

An example

以下是一个使用装饰器设计模式的具体例子,这个例子展示如何为一个简单的咖啡类添加不同的“调料”或“装饰”,比如加奶或加糖。

首先,我们定义一个Coffee接口,它有一个getCost()方法和一个getDescription()方法:

public interface Coffee {  double getCost();  String getDescription();  
}

然后,我们创建一个实现了Coffee接口的简单咖啡类SimpleCoffee

public class SimpleCoffee implements Coffee {  @Override  public double getCost() {  return 2.0;  }  @Override  public String getDescription() {  return "Simple Coffee";  }  
}

接下来,我们定义一个装饰器基类CoffeeDecorator,它也实现了Coffee接口,并持有一个Coffee对象的引用:

public abstract class CoffeeDecorator implements Coffee {  protected Coffee coffee;  public CoffeeDecorator(Coffee coffee) {  this.coffee = coffee;  }  @Override  public double getCost() {  return coffee.getCost();  }  @Override  public String getDescription() {  return coffee.getDescription();  }  
}

现在,我们可以创建具体的装饰器类,比如MilkDecorator(加奶的装饰器)和SugarDecorator(加糖的装饰器):

public class MilkDecorator extends CoffeeDecorator {  public MilkDecorator(Coffee coffee) {  super(coffee);  }  @Override  public double getCost() {  return super.getCost() + 0.5; // 假设加奶增加0.5元  }  @Override  public String getDescription() {  return super.getDescription() + ", Milk";  }  
}  public class SugarDecorator extends CoffeeDecorator {  public SugarDecorator(Coffee coffee) {  super(coffee);  }  @Override  public double getCost() {  return super.getCost() + 0.3; // 假设加糖增加0.3元  }  @Override  public String getDescription() {  return super.getDescription() + ", Sugar";  }  
}

最后,我们创建一个客户端类来测试这些装饰器:

public class CoffeeShop {  public static void main(String[] args) {  Coffee coffee = new SimpleCoffee();  System.out.println("Cost: " + coffee.getCost() + ", Description: " + coffee.getDescription());  coffee = new MilkDecorator(coffee);  System.out.println("Cost: " + coffee.getCost() + ", Description: " + coffee.getDescription());  coffee = new SugarDecorator(coffee);  System.out.println("Cost: " + coffee.getCost() + ", Description: " + coffee.getDescription());  // 也可以先加糖再加奶  Coffee anotherCoffee = new SimpleCoffee();  anotherCoffee = new SugarDecorator(anotherCoffee);  anotherCoffee = new MilkDecorator(anotherCoffee);  System.out.println("Cost: " + anotherCoffee.getCost() + ", Description: " + anotherCoffee.getDescription());  }  
}

运行CoffeeShopmain方法,你将看到不同装饰器对咖啡成本和描述的影响。这就是装饰器设计模式的一个具体实现,它允许我们在运行时动态地给对象添加新的责任(比如加奶或加糖),同时保持代码的灵活性和可扩展性。

3 🍌Behavioral patterns

3.1 Strategy

有多种不同的算法来实现同一个任务,但需要client根据需要 动态切换算法,而不是写死在代码里

在这里插入图片描述

在这里插入图片描述

public interface PaymentStrategy {public void pay(int amount);
}public class CreditCardStrategy implements PaymentStrategy {private String name;private String cardNumber;private String cvv;private String dateOfExpiry;public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){this.name=nm;this.cardNumber=ccNum;this.cvv=cvv;this.dateOfExpiry=expiryDate;}@Overridepublic void pay(int amount) {System.out.println(amount +" paid with credit card");}
}public class PaypalStrategy implements PaymentStrategy {private String emailId;private String password;public PaypalStrategy(String email, String pwd){this.emailId=email;this.password=pwd;}@Overridepublic void pay(int amount) {System.out.println(amount + " paid using Paypal.");}
}

策略设计模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。策略模式使得算法可以独立于使用它的客户端变化。

在给出的代码中,我们可以看到以下组成部分:

  1. 策略接口 (PaymentStrategy):
    定义了一个支付策略的公共接口,即pay(int amount)方法。客户端代码将使用此接口与不同的支付策略交互,而无需知道它们的具体实现。
  2. 具体策略 (CreditCardStrategyPaypalStrategy):
    这两个类分别实现了PaymentStrategy接口,提供了不同的支付算法实现。它们分别对应于使用信用卡和PayPal进行支付的逻辑。
    • CreditCardStrategy类保存了信用卡的相关信息(如持卡人姓名、卡号、CVV和到期日期),但在pay方法中并没有使用这些信息,只是简单地打印了一条消息。在实际应用中,这些信息可能会被用来与信用卡处理系统交互以完成支付。
    • PaypalStrategy类保存了PayPal账户的相关信息(如电子邮件和密码),但同样在pay方法中并没有使用这些信息,只是打印了一条消息。在实际应用中,这些信息可能会被用来与PayPal系统交互以完成支付。
  3. 客户端代码
    客户端代码通常会包含一个PaymentStrategy类型的变量,并使用它来执行支付操作。客户端代码可以通过在运行时动态地更改此变量的类型来选择不同的支付策略。

下面是一个简单的客户端代码示例,展示了如何使用这些策略:

public class PaymentClient {  private PaymentStrategy paymentStrategy;  public PaymentClient(PaymentStrategy strategy) {  this.paymentStrategy = strategy;  }  public void makePayment(int amount) {  paymentStrategy.pay(amount);  }  public static void main(String[] args) {  PaymentClient client = new PaymentClient(new CreditCardStrategy("John Doe", "1234567890123456", "123", "12/25"));  client.makePayment(100); // 100 paid with credit card  client = new PaymentClient(new PaypalStrategy("user@example.com", "password"));  client.makePayment(50);  // 50 paid using Paypal.  }  
}

在这个示例中,PaymentClient类封装了对支付策略的引用,并提供了makePayment方法来执行支付操作。通过向PaymentClient构造函数传入不同的PaymentStrategy对象,我们可以动态地更改其使用的支付策略。

3.2 Template Method

做事情的步骤一样,但具体方法不同;共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现

在这里插入图片描述

Template Method设计模式是一种行为设计模式,它在一个方法中定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。

public abstract class OrderProcessTemplate {public boolean isGift;public abstract void doSelect();public abstract void doPayment();public void giftWrap() {System.out.println("Gift wrap done.");
}public abstract void doDelivery();public final void processOrder() {doSelect();doPayment();if (isGift)giftWrap();doDelivery();}
}public class NetOrder extends OrderProcessTemplate {@Overridepublic void doSelect() {}@Overridepublic void doPayment() {}@Overridepublic void doDelivery() {}
}

3.3 Iterator

客户端希望遍历被放入 容器/集合类的一组ADT对象,无需关心容器的具体类型

也就是说,不管对象被放进哪里,都应该提供同样的遍历方式

在这里插入图片描述

Iterable接口:实现该接口的集合对象是可迭代遍历的

public interface Iterable<T> {...Iterator<T> iterator();
}

Iterator接口:迭代器

public interface Iterator<E> {boolean hasNext();E next();void remove();
}

Iterator pattern:让自己的集合类实现Iterable接口,并实现自己的独特Iterator迭代器(hasNext, next, remove),允许客户端利用这个 迭代器进行显式或隐式的迭代遍历:

在这里插入图片描述

迭代器设计模式包含以下几个主要角色:

  1. 迭代器(Iterator):
    • 定义一个访问聚合对象元素但不暴露其内部表示的接口。
    • 提供遍历聚合对象的方法,如hasNext()(检查是否还有下一个元素)和next()(获取下一个元素)。
  2. 具体迭代器(ConcreteIterator):
    • 实现迭代器接口,并跟踪遍历中的当前位置。
    • 使用聚合对象的内部表示法来遍历元素。
  3. 聚合(Aggregate):
    • 定义创建迭代器对象的接口。
    • 通常是包含一组元素的类,如列表、集合等。
  4. 具体聚合(ConcreteAggregate):
    • 实现聚合接口,返回具体迭代器的实例。
    • 在具体聚合中,通常包含存储元素的私有成员变量。

下面是一个简单的Java示例,展示了迭代器设计模式的基本用法:

// 聚合接口  
interface Aggregate {  Iterator createIterator();  
}  // 迭代器接口  
interface Iterator {  boolean hasNext();  Object next();  
}  // 具体聚合(例如一个列表)  
class MyList implements Aggregate {  private List<Object> elements = new ArrayList<>();  // 添加元素的方法  public void add(Object element) {  elements.add(element);  }  // 创建迭代器的方法  @Override  public Iterator createIterator() {  return new MyListIterator(this);  }  // 内部类:具体迭代器  private class MyListIterator implements Iterator {  private int currentIndex = 0;  private MyList list;  public MyListIterator(MyList list) {  this.list = list;  }  @Override  public boolean hasNext() {  return currentIndex < list.elements.size();  }  @Override  public Object next() {  if (!hasNext()) {  throw new NoSuchElementException();  }  return list.elements.get(currentIndex++);  }  }  
}  // 客户端代码  
public class Client {  public static void main(String[] args) {  MyList list = new MyList();  list.add("Element 1");  list.add("Element 2");  list.add("Element 3");  Iterator iterator = list.createIterator();  while (iterator.hasNext()) {  System.out.println(iterator.next());  }  }  
}

显示的迭代

在这个示例中,MyList类实现了Aggregate接口,并提供了创建迭代器的方法。MyListIteratorMyList的内部类,实现了Iterator接口,并用于遍历MyList中的元素。客户端代码通过调用createIterator()方法获取迭代器,并使用迭代器遍历聚合对象中的元素。

An example of Iterator pattern

public class Pair<E> implements Iterable<E> {private final E first, second;public Pair(E f, E s) { first = f; second = s; }public Iterator<E> iterator() {return new PairIterator();}private class PairIterator implements Iterator<E> {private boolean seenFirst = false, seenSecond = false;public boolean hasNext() { return !seenSecond; }public E next() {if (!seenFirst) { seenFirst = true; return first; }if (!seenSecond) { seenSecond = true; return second; }throw new NoSuchElementException();}public void remove() {throw new UnsupportedOperationException();}}
}

在这里插入图片描述

尽管for-each循环在语法上看起来像是隐式迭代,但实际上它仍然依赖于Iterable接口和Iterator的实现来工作。在运行时,Java会调用iterable.iterator()来获取迭代器,并使用迭代器的hasNext()next()方法来遍历元素。因此,虽然从语法上看似隐式,但从实现上看,迭代仍然是显式的。(for-each循环是Java提供的一种语法糖,用于简化对实现了Iterable<E>接口集合的遍历。)

3.4 Visitor

在这里插入图片描述

/* Abstract element interface (visitable) */
public interface ItemElement {public int accept(ShoppingCartVisitor visitor);
}/* Concrete element */
public class Book implements ItemElement{private double price;...int accept(ShoppingCartVisitor visitor) {visitor.visit(this);}
}public class Fruit implements ItemElement{private double weight;...int accept(ShoppingCartVisitor visitor) {visitor.visit(this);}
}

代码展示了Visitor设计模式中的一部分,包括一个抽象元素接口(ItemElement)和两个具体的元素类(BookFruit)。这里我会逐一分析并解释代码。

抽象元素接口ItemElement

/* Abstract element interface (visitable) */  
public interface ItemElement {  public int accept(ShoppingCartVisitor visitor);  
}
  • 接口定义ItemElement 是一个接口,它定义了一个名为 accept 的方法,该方法接受一个类型为 ShoppingCartVisitor 的参数,并返回一个整数。这个接口表示可以被访问(或称为“可访问的”)的元素。
  • 方法 accept:这个方法用于允许一个 ShoppingCartVisitor 对象“访问”当前的元素对象。accept 方法中通常不会包含任何具体的业务逻辑,它只是调用传入的 visitor 对象的 visit 方法,并将当前对象(this)作为参数传递。

具体元素类

Book

/* Concrete element */  
public class Book implements ItemElement{  private double price;  // ... 其他成员变量和方法 ...  int accept(ShoppingCartVisitor visitor) {  visitor.visit(this);  }  
}
  • 类定义Book 类实现了 ItemElement 接口,这意味着它必须提供 accept 方法的实现。
  • 方法 acceptBook 类的 accept 方法按照 ItemElement 接口的定义实现了对 ShoppingCartVisitor 的访问。当 accept 方法被调用时,它会将 this(即当前的 Book 对象)传递给 visitor 对象的 visit 方法。
  • 注意accept 方法应该是 public 的,因为接口中的方法默认是 public 的。但是在您提供的 Book 类的定义中,accept 方法是默认的包级私有访问权限(即没有显式地声明为 public)。这会导致编译错误,因为子类必须实现接口中的所有方法,并且这些方法的访问级别必须与接口中定义的访问级别相匹配。

Fruit

public class Fruit implements ItemElement{  private double weight;  // ... 其他成员变量和方法 ...  int accept(ShoppingCartVisitor visitor) {  visitor.visit(this);  }  
}
  • 类定义Fruit 类同样实现了 ItemElement 接口,并且也需要提供一个 accept 方法的实现。
  • 方法 accept:与 Book 类类似,Fruit 类的 accept 方法也是将当前对象(this)传递给 visitor 对象的 visit 方法。
  • 同样的问题accept 方法也应该是 public 的,否则会导致编译错误。

总结

代码展示了Visitor设计模式的一部分,但是有几个地方需要注意:

  1. accept 方法的访问级别:在 BookFruit 类中,accept 方法应该是 public 的,以便它们可以正确地实现 ItemElement 接口。
  2. ShoppingCartVisitor 接口:虽然您没有提供 ShoppingCartVisitor 接口的定义,但根据代码中的使用,我们可以推测它应该定义了一个或多个 visit 方法,这些方法接受不同类型的 ItemElement(例如 BookFruit)作为参数。
  3. 返回类型accept 方法返回了一个整数。在Visitor模式中,这通常用于表示操作的结果或状态,但在某些情况下,该方法也可能返回 void
  4. 方法的实际业务逻辑:通常,在 accept 方法内部不直接执行业务逻辑,而是在 visitorvisit 方法中执行。这样,您就可以在不修改元素类的情况下添加新的操作。
/* Abstract visitor interface */
public interface ShoppingCartVisitor { int visit(Book book); int visit(Fruit fruit); 
} public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {public int visit(Book book) {int cost=0;if(book.getPrice() > 50){cost = book.getPrice()-5;}else cost = book.getPrice();System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost);return cost;}public int visit(Fruit fruit) {int cost = fruit.getPricePerKg()*fruit.getWeight();System.out.println(fruit.getName() + " cost = "+cost);return cost;}
}

4 🫐Commonality and Difference of Design Patterns

4.1 共性样式1

只使用“继承”,不使用“delegation” 核心思路:OCP/DIP 依赖反转,客户端只依赖“抽象”,不能 依赖于“具体” 发生变化时最好是“扩展”而不是“修改”

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.2 共性样式2

两棵“继承树”,两个层次的“delegation”

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

相关文章:

软件构造 | Design Patterns for Reuse and Maintainability

Design Patterns for Reuse and Maintainability &#xff08;面向可复用性和可维护性的设计模式&#xff09; Open-Closed Principle (OCP) ——对扩展的开放&#xff0c;对修改已有代码的封 Why reusable design patterns A design… …enables flexibility to change …...

Python数据分析-股票分析和可视化(深证指数)

一、内容简介 股市指数作为衡量股市整体表现的重要工具&#xff0c;不仅反映了市场的即时状态&#xff0c;也提供了经济健康状况的关键信号。在全球经济体系中&#xff0c;股市指数被广泛用于预测经济活动&#xff0c;评估投资环境&#xff0c;以及制定财政和货币政策。在中国…...

Linux如何安装openjdk1.8

文章目录 Centosyum安装jdk和JRE配置全局环境变量验证ubuntu使用APT(适用于Ubuntu 16.04及以上版本)使用PPA(可选,适用于需要特定版本或旧版Ubuntu)Centos yum安装jdk和JRE yum install java-1.8.0-openjdk-devel.x86_64 安装后的目录 配置全局环境变量 vim /etc/pr…...

【LLVM】LTO学习

看这篇文章&#xff0c;文中的代码都是错的&#xff0c;给出的命令行也是错的。 真不如参考文献中也是华为的外国员工写的PPT。 但是&#xff0c;上述的文件中的指令也存在报错&#xff0c;还是官方文档看着舒服。...

事务的特性-原子性(Atomicity)、一致性(Consistency)、隔离性(Asolation)、持久性(Durability)

一、引言 1、数据库管理系统DBMS为保证定义的事务是一个逻辑工作单元&#xff0c;达到引入事务的目的&#xff0c;实现的事务机制要保证事务具有原子性、一致性、隔离性和持久性&#xff0c;事务的这四个特性也统称为事务的ACID特性 2、当事务保持了ACID特性&#xff0c;才能…...

redis哨兵模式(Redis Sentinel)

哨兵模式的背景 当主服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费事费力&#xff0c;还会造成一段时间内服务不可用。这不是一种推荐的方式。 为了解决单点故障和提高系统的可用性&#xff0c;需要一种自动化的监…...

【牛客】牛客小白月赛97 题解 A - E

文章目录 A - 三角形B - 好数组C - 前缀平方和序列D - 走一个大整数迷宫E - 前缀和前缀最大值 A - 三角形 map存一下每个数出现了多少次&#xff0c;再遍历map #include <bits/stdc.h>using namespace std;#define int long long using i64 long long;typedef pair<…...

Spring Boot中泛型参数的灵活运用:最佳实践与性能优化

泛型是Java中一种强大的特性&#xff0c;它提供了编写通用代码的能力&#xff0c;使得代码更加灵活和可复用。在Spring Boot应用程序中&#xff0c;泛型参数的灵活运用可以带来诸多好处&#xff0c;包括增强代码的可读性、提高系统的健壮性以及优化系统的性能。本文将深入探讨在…...

MySQL建表时的注意事项

以下是我对MySQL建表时的注意事项。其实&#xff0c;建表事项有很多&#xff0c;我的总结如下&#xff1a; 1 存储引擎的选择&#xff0c;一般做开发&#xff0c;都是要支持事务的&#xff0c;所以选择InnoDB 2 对字段类型的选择&#xff1a; ​ 对于日期类型如果要记录时分…...

Advanced RAG 09:『提示词压缩』技术综述

编者按&#xff1a; 如何最大限度地发挥 LLMs 的强大能力&#xff0c;同时还能控制其推理成本&#xff1f;这是当前业界研究的一个热点课题。 针对这一问题&#xff0c;本期精心选取了一篇关于"提示词压缩"(Prompt Compression)技术的综述文章。正如作者所说&#xf…...

(13)DroneCAN 适配器节点(二)

文章目录 前言 2 固件 2.1 基于F103 2.2 基于F303 2.3 基于F431 3 ArduPilot固件DroneCAN设置 3.1 f303-通用设置示例 4 DroneCAN适配器节点 前言 这些节点允许现有的 ArduPilot 支持的外围设备作为 DroneCAN 或 MSP 设备适应 CAN 总线。这也允许扩展自动驾驶仪硬件的…...

摸鱼大数据——Spark基础——Spark环境安装——Spark Local[*]搭建

一、虚拟机配置 查看每一台的虚拟机的IP地址和网关地址 查看路径: cat /etc/sysconfig/network-scripts/ifcfg-ens33 2.修改 VMware的网络地址: 使用VMnet8 3.修改windows的对应VMware的网卡地址 4.通过finalshell 或者其他的shell连接工具即可连接使用即可, 连接后, 测试一…...

函数内部结构分层浅析(从MVC分层架构联想)

函数内部结构分层浅析&#xff08;从MVC分层架构联想&#xff09; 分层架构:一种将软件代码按不同功能进行划分的架构模式。 优点包括&#xff1a; 可维护性&#xff1a;各层职责明确&#xff0c;易于单独修改维护。 可扩展性&#xff1a;方便添加或修改某一层&#xff0c;不…...

【three.js案例二】时空隧道

import * as THREE from ./build/three.module.js // 引入轨道控制器扩展库OrbitControls.js import { OrbitControls } from three/addons/controls/OrbitControls.js; // 引入dat.gui.js的一个类GUI import { GUI } from three/addons/libs/lil-gui.module.min.js;// 场景 co…...

动手学深度学习(Pytorch版)代码实践 -计算机视觉-48全连接卷积神经网络(FCN)

48全连接卷积神经网络&#xff08;FCN&#xff09; 1.构造函数 import torch import torchvision from torch import nn from torch.nn import functional as F import matplotlib.pyplot as plt import liliPytorch as lp from d2l import torch as d2l# 构造模型 pretrained…...

【Python游戏】猫和老鼠

本文收录于 《一起学Python趣味编程》专栏,从零基础开始,分享一些Python编程知识,欢迎关注,谢谢! 文章目录 一、前言二、代码示例三、知识点梳理四、总结一、前言 本文介绍如何使用Python的海龟画图工具turtle,开发猫和老鼠游戏。 什么是Python? Python是由荷兰人吉多范…...

【无标题】c# WEBAPI 读写表到Redis

//c# WEBAPI 读写表到Redis using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using Newtonsoft.Json; using StackExchange.Redis; using System.Data; using System.Web; namespace …...

【剑指Offer系列】53-0到n中缺失的数字(index)

给定一个包含 [0, n] 中 n 个数的数组 nums &#xff0c;找出 [0, n] 这个范围内没有出现在数组中的那个数。 示例 1&#xff1a; 输入&#xff1a;nums [3,0,1] 输出&#xff1a;2 解释&#xff1a;n 3&#xff0c;因为有 3 个数字&#xff0c;所以所有的数字都在范围 [0,3]…...

docker compose部署zabbix7.0官方方法快速搭建

环境介绍&#xff1a; 系统&#xff1a;centos7 官方文档&#xff1a;https://www.zabbix.com/documentation/current/zh/manual/installation/containers docker镜像加速 vi /etc/docker/daemon.json{"registry-mirrors": ["https://docker.1panel.live&quo…...

分库分表之后如何设计主键ID(分布式ID)?

文章目录 1、数据库的自增序列步长方案2、分表键结合自增序列3、UUID4、雪花算法5、redis的incr方案总结 在进行数据库的分库分表操作后&#xff0c;必然要面临的一个问题就是主键id如何生成&#xff0c;一定是需要一个全局的id来支持&#xff0c;所以分库分表之后&#xff0c;…...

秋招突击——6/28、6.29——复习{数位DP——度的数量}——新作{}

文章目录 引言复习数位DP——度的数量个人实现参考实现 总结 引言 头一次产生了那么强烈的动摇&#xff0c;对于未来没有任何的感觉的&#xff0c;不知道将会往哪里走&#xff0c;不知道怎么办。可能还是因为实习吧&#xff0c;再加上最近复习也没有什么进展&#xff0c;并不知…...

Spring Boot中使用Thymeleaf进行页面渲染

Spring Boot中使用Thymeleaf进行页面渲染 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot应用中使用Thymeleaf模板引擎进行页面…...

恢复策略(下)-事务故障后的数据库恢复、系统故障后的数据库恢复(检查点技术)、介质故障后的数据库恢复

一、数据库恢复-事务故障 系统通过对事物进行UNDO操作和REDO操作可实现故障后的数据库状态恢复 1、对于发生事务故障后的数据库恢复 恢复机制在不影响其他事务运行的情况下&#xff0c;强行回滚夭折事务&#xff0c;对该事务进行UNDO操作&#xff0c;来撤销该事务已对数据库…...

如何知道docker谁占用的显卡的显存?

文章目录 python环境安装nvidia-htop查看pid加一个追踪总结一下【找到容器创建时间】使用说明示例 再总结一下【用PID找到容器创建时间&#xff0c;从而找到谁创建的】使用说明示例 python环境安装nvidia-htop nvidia-htop是一个看详细的工具。 pip3 install nvidia-htop查看…...

wps linux node.js 加载项开发,和离线部署方案

环境准备 windwos 安装node.js 安装VSCode 安装wps linux 安装node.js 安装VSCode 安装wps 通过npm 安装wpsjs SDK 使用npm安装wpsjs npm install -g wpsjs 创建一个项目 wpsjs create WPS-Addin-PPT 创建项目会让你选择2个东西&#xff1a; 1&#xff1a;选择你的文…...

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇Kerberos委派安全非约束系约束系RBCD资源系Spooler利用

红队内网攻防渗透 1. 内网横向移动1.1 委派安全知识点1.1.1 域委派分类1.1.2 非约束委派1.1.2.1 利用场景1.1.2.2 复现配置:1.1.2.3 利用思路1:诱使域管理员访问机器1.1.2.3.1 利用过程:主动通讯1.1.2.3.2 利用过程:钓鱼1.1.2.4 利用思路2:强制结合打印机漏洞1.1.2.5 利用…...

nginx上传文件限制

默认限制 Nginx 限制文件大小可以通过 client_max_body_size 指令来设置&#xff0c;该指令通常在 http、server 或 location 块中设置&#xff0c;如果不设置&#xff0c;默认上传大小为1M。 修改上传文件限制 要修改Nginx的文件上传大小限制&#xff0c;你需要编辑Nginx的配…...

76. 最小覆盖子串(困难)

76. 最小覆盖子串 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;76. 最小覆盖子串 2.详细题解 在s中寻找一个最短的子串&#xff0c;使之包含t中的所有字符&#xff0c;t中可能存在多个相同字符&#xff0c;寻找的子串也应至少含有…...

K8S 集群节点扩容

环境说明&#xff1a; 主机名IP地址CPU/内存角色K8S版本Docker版本k8s231192.168.99.2312C4Gmaster1.23.1720.10.24k8s232192.168.99.2322C4Gwoker1.23.1720.10.24k8s233&#xff08;需上线&#xff09;192.168.99.2332C4Gwoker1.23.1720.10.24 当现有集群中的节点资源不够用&…...

AI大模型技术在音乐创造的应用前景

大模型技术在音乐创作领域具有广阔的应用前景&#xff0c;可以为音乐家、作曲家和音乐爱好者提供以下方面的帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 音乐创作辅助&#xff1a;大模型可以帮助音乐家和作曲家生成旋律、和声…...

Linux多进程和多线程(一)-进程的概念和创建

进程 进程的概念进程的特点如下进程和程序的区别LINUX进程管理 getpid()getppid() 进程的地址空间虚拟地址和物理地址进程状态管理进程相关命令 ps toppstreekill 进程的创建 并发和并行fork() 父子进程执行不同的任务创建多个进程 进程的退出 exit()和_exit() exit()函数让当…...

熊猫烧香是什么?

熊猫烧香&#xff08;Worm.WhBoy.cw&#xff09;是一种由李俊制作的电脑病毒&#xff0c;于2006年底至2007年初在互联网上大规模爆发。这个病毒因其感染后的系统可执行文件图标会变成熊猫举着三根香的模样而得名。熊猫烧香病毒具有自动传播、自动感染硬盘的能力&#xff0c;以及…...

使用Vue3和Tailwind CSS快速搭建响应式布局

### 第一部分&#xff1a;初始化Vue3项目并安装Tailwind CSS 首先&#xff0c;在你的开发环境中打开终端&#xff0c;然后通过Vue CLI来创建一个新的Vue3项目。输入如下命令&#xff1a; vue create my-vue-app 按照提示选择Vue3的相关选项&#xff0c;创建完毕后&#xff0…...

J019_选择排序

一、排序算法 排序过程和排序原理如下图所示&#xff1a; 二、代码实现 package com.itheima.sort;import java.util.Arrays;public class SelectSort {public static void main(String[] args) {int[] arr {5, 4, 3, 1, 2};//选择排序for (int i 0; i < arr.length - 1…...

【linux】vim的使用

目录 一、Vim的基本模式 二、Vim的常见命令 三、Vim的高级用法 四、Vim的进阶使用技巧 在Linux系统中&#xff0c;Vim是一款功能强大的文本编辑器&#xff0c;特别适用于程序员的代码编辑和修改。以下是Vim的详细使用教程&#xff0c;包括其基本模式、常见命令和高级用法。…...

【工具测评】ONLYOFFICE8.1版本桌面编辑器测评:好用!

随着远程工作的普及和数字化办公的发展&#xff0c;越来越多的人开始寻找功能强大、易于使用的办公软件。在这个背景下&#xff0c;ONLYOFFICE 8.1应运而生&#xff0c;成为许多用户的新选择。ONLYOFFICE 8.1是一款办公套件软件&#xff0c;提供文档处理、电子表格和幻灯片制作…...

核方法总结(四)——高斯过程回归学习笔记

一、定义 基于核方法的线性回归模型和传统线性回归一样&#xff0c;可以用未知数据进行预测&#xff0c;但不能确定 预测的可信度。在参考书第二章中可知&#xff0c;基于贝叶斯方法可以实现对未知数据依概率预测&#xff0c;进而可得到预测的可信度。这一方法中&#xff0c;通…...

【Python3的内置函数和使用方法】

目录 Python 特点 Python 中文编码 Python 变量类型 Python列表 Python 元组 元组是另一个数据类型&#xff0c;类似于 List&#xff08;列表&#xff09; Python 字典 Python数据类型转换 Python 运算符 Python算术运算符 Python比较运算符 Python赋值运算符 Pyt…...

递推算法计算信号特征

在线算法&#xff08;在线计算或递推计算&#xff09;能够在不存储全部数据的情况下逐步更新信号的特征信息&#xff0c;非常适合资源受限的单片机应用场景。 用途&#xff1a;单片机边采集&#xff21;&#xff24;&#xff23;边计算&#xff0c;最终将采集的信号特征计算结果…...

spring-boot-configuration-processor注释处理器

开源项目SDK&#xff1a;https://github.com/mingyang66/spring-parent 个人文档&#xff1a;https://mingyang66.github.io/raccoon-docs/#/ spring-boot-configuration-processor是springboot提供的一个注释处理器&#xff08;annotation processor&#xff09;,它用于在编译…...

Python和MATLAB粘性力接触力动态模型半隐式欧拉算法

&#x1f3af;要点 &#x1f3af;运动力模型计算制作过程&#xff1a;&#x1f58a;相机捕捉网球运动图&#xff0c;制定运动数学模型&#xff0c;数值微分运动方程 | &#x1f58a;计算运动&#xff0c;欧拉算法离散积分运动&#xff0c;欧拉-克罗默算法微分运动方程 &#…...

webstorm无法识别tsconfig.json引用项目配置文件中的路径别名

问题 vite项目模板中&#xff0c;应用的ts配置内容写在tsconfig.app.json文件中&#xff0c;并在tsconfig.json通过项目引用的方式导入 {"files": [],"references": [{"path": "./tsconfig.app.json"},{"path": "./t…...

qiankun微前端:qiankun+vite+vue3+ts(未完待续..)

目录 什么是微前端 目前现有的微前端 好处 使用 子应用的页面在主应用里显示 什么是微前端 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 我的理解就是将一个大型的前端应用拆分成多个模块&#xff0c;每个微前端模块可以由…...

001:开源交易系统开发实战开篇

本专栏采用融入【主力思维】的方法学&#xff0c;包含数据抓取、特征模型开发、历史验证回归测试、每日动态风险评估管理等技术&#xff0c;较大的增强股票投资胜率&#xff0c;让IT开发者拥有一套属于自己思路的专用交易软件。 先简要介绍系统成功和项目&#xff0c;后续持续…...

Pytorch实战(一):LeNet神经网络

文章目录 一、模型实现1.1数据集的下载1.2加载数据集1.3模型训练1.4模型预测 LeNet神经网络是第一个卷积神经网络&#xff08;CNN&#xff09;&#xff0c;首次采用了卷积层、池化层这两个全新的神经网络组件&#xff0c;接收灰度图像&#xff0c;并输出其中包含的手写数字&…...

RabbitMq的基础及springAmqp的使用

RabbitMq 官网:RabbitMQ: One broker to queue them all | RabbitMQ 什么是MQ&#xff1f; mq就是消息队列&#xff0c;消息队列遵循这先入先出原则。一般用来解决应用解耦&#xff0c;异步消息&#xff0c;流量削峰等问题&#xff0c;实现高性能&#xff0c;高可用&#xf…...

uniapp uniCloud云开发

uniCloud概述 uniCloud 是 DCloud 联合阿里云、腾讯云、支付宝云&#xff0c;为开发者提供的基于 serverless 模式和 js 编程的云开发平台。 uniCloud 的 web控制台地址&#xff1a;https://unicloud.dcloud.net.cn 文档&#xff1a;https://doc.dcloud.net.cn/uniCloud/ un…...

智能扫地机,让生活电器更加便民-NV040D扫地机语音方案

一、语音扫地机开发背景&#xff1a; 随着人工智能和物联网技术的飞速发展&#xff0c;智能家居设备已成为现代家庭不可或缺的一部分。其中&#xff0c;扫地机作为家庭清洁的重要工具&#xff0c;更是得到了广泛的关注和应用。 然而&#xff0c;传统的扫地机在功能和使用上仍存…...

【后端面试题】【中间件】【NoSQL】ElasticSearch索引机制和高性能的面试思路

Elasticsearch的索引机制 Elasticsearch使用的是倒排索引&#xff0c;所谓的倒排索引是相对于正排索引而言的。 在一般的文件系统中&#xff0c;索引是文档映射到关键字&#xff0c;而倒排索引则相反&#xff0c;是从关键字映射到文档。 如果没有倒排索引的话&#xff0c;想找…...

【漏洞复现】时空智友ERP updater.uploadStudioFile接口处存在任意文件上传

0x01 产品简介 时空智友ERP是一款基于云计算和大数据技术的企业资源计划管理系统。该系统旨在帮助企业实现数字化转型&#xff0c;提高运营效率、降低成本、增强决策能力和竞争力&#xff0c;时空智友ERP系统涵盖了企业的各个业务领域&#xff0c;包括财务管理、供应链管理、生…...

MySQL的Geometry数据处理之WKB方案

MySQL的Geometry数据处理之WKT方案&#xff1a;https://blog.csdn.net/qq_42402854/article/details/140134357 MySQL的Geometry数据处理之WKT方案中&#xff0c;介绍WTK方案的优点&#xff0c;也感受到它的繁琐和缺陷。比如&#xff1a; 需要借助 ST_GeomFromText和 ST_AsTex…...

C语言字节对齐技术在嵌入式、网络与操作系统中的应用与优化

第一部分&#xff1a;嵌入式系统中的字节对齐 嵌入式系统通常对性能和资源有着严格的要求。在这些系统中&#xff0c;字节对齐的正确使用可以显著提高数据访问速度&#xff0c;减少内存占用&#xff0c;并提高系统的整体效率。 一、嵌入式系统中的字节对齐挑战 嵌入式系统中…...

6域名系统DNS

《计算机网络》第7版&#xff0c;谢希仁 每次记不清楚的知识点&#xff0c;通过上网查找&#xff0c;总是只能看到很零碎的答案。最后还是最喜欢看这个版本的书&#xff0c;一看就回忆起来了&#xff0c;逻辑严谨&#xff0c;循循善诱&#xff0c;知识讲解的全面又清晰&#xf…...

简述Vue中的数据双向绑定原理

Vue中的数据双向绑定原理是Vue框架的核心特性之一&#xff0c;它通过数据劫持结合发布者-订阅者模式来实现。下面将详细阐述Vue中数据双向绑定的原理&#xff0c;并尽量按照清晰的结构进行归纳&#xff1a; 一、数据劫持 使用Object.defineProperty()&#xff1a; Vue在组件…...

优化接口的几个常用方法

优化Java接口性能是确保应用程序高效、响应迅速且能够处理负载的重要步骤。以下是一些优化Java接口的方法&#xff0c;涵盖从设计模式、代码优化到使用牛刀小试工具的综合技巧。以下是我在工作中总结的几个方面&#xff1a; 设计模式和接口设计使用缓存优化数据库访问异步处理…...

在Linux上部署和管理OpenStack云平台

部署和管理OpenStack云平台在Linux上是一个相当复杂的任务&#xff0c;涉及到多个组件和服务的配置和集成。下面是一个简化的步骤概述&#xff0c;用于在Linux上部署和管理OpenStack云平台&#xff1a; 1. 环境准备: • 确保你有足够数量的服务器作为控制节点、计算节点、网络…...

“翼”起降本盈运增效!欧曼星翼PRO自动挡中卡引领区域集散运输发展新趋势

在当前运输行业中,随着运价偏低、燃料价格偏高等因素影响,卡友对性价比更高的运输装备需求越发迫切。这一情况不止在重卡领域备受关注,在中卡行业里也成为卡友的心头大事!积极响应行业发展趋势,欧曼以重卡平台+自动挡双重赋能打造的欧曼星翼PRO自动挡中卡即将上市,深度契合用户…...

发挥直接融资支撑作用助力发展新质生产力

多位专家5月27日在“布雷顿森林体系:过去80年与未来展望”国际会议暨2024清华五道口全球金融论坛上表示,建设金融强国要看重质量和功能,从数量驱动到质量引领是建设金融强国的必由之路。同时,在发展新质生产力的过程中,直接融资可发挥重要支撑作用,应进一步推动我国多层次…...

国际儿童慈善组织:苏丹超1800万儿童失学超过一年

当地时间5月28日,国际儿童慈善组织救助儿童会发表声明称,自苏丹武装冲突爆发以来,针对苏丹学校和教育设施的暴力袭击事件增长了三倍。截至目前,苏丹国内已发生88起此类暴力事件。这些暴力袭击包括:对学校的空袭,造成师生伤亡;对教师施加酷刑,杀害和绑架老师以及在教育设…...

canfd与can2.0关系

canfd是can2.0的升级版&#xff0c; 支持canfd的设备就支持can2.0&#xff0c;但can2.0的设备不支持canfd 参考 是选CAN接口卡还是CANFD接口卡_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Hh411K7Zn/?spm_id_from333.999.0.0 哪些STM32有CANFD外设 STM32G0, STM…...

ZJGSU 2199 图论1

描述 某省调查城镇交通状况&#xff0c;得到现有城镇道路统计表&#xff0c;表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通&#xff08;但不一定有直接的道路相连&#xff0c;只要互相间接通过道路可达即可&#xff09;。问…...

Angular中,@HostListener装饰器

HostListener(input, [$event]) onInput(event: KeyboardEvent) {// 将输入值转换为大写const currentValue this.el.nativeElement.value;const upperCaseValue currentValue.toUpperCase();// 更新输入框的值if (currentValue ! upperCaseValue) {this.el.nativeElement.va…...