设计模式之开篇

在软件开发的世界里,设计模式有如一本精妙的工程艺术指导准则,为我们提供了解决常见问题的优雅实现方案。然而,有些程序员可能会认为设计模式太过繁琐,一个简单的 if/else 语句就能解决问题,何必费心去学习这些看似复杂的概念呢?在这个系列的文章里,我和大家一起探讨为什么设计模式是值得的,以及如何在实际开发中去融入设计模式的思想。

一、为什么学设计模式

1、代码质量和可维护性

拥有设计模式的思维方式,意味着你不仅仅是在写能够工作的代码,更是在构建具有良好结构的、易于理解和维护的代码。设计模式是过去经验的总结,它们提供了在各种场景下验证过的最佳实践,有助于避免常见的陷阱和错误。

2、可扩展性和灵活性

需求总是在变化的,永远不可能存在一层不变的需求,而设计模式可以为你的代码提供更好的扩展性。通过采用开放封闭等设计原则,你的代码可以更容易地适应新的功能需求,而不需要对原有的代码进行大规模修改。

3、团队协作

设计模式是一种通用的编程语言,它提供了一种共享的术语和理解方式,有助于团队成员更容易理解和协作。当所有人都熟悉常见的设计模式时,交流就会变得更加高效,合作更加顺畅。

二、怎么样学设计模式

1、刻意实践

在日常编码中刻意使用设计模式是学习的最佳途径。不要觉得使用设计模式会让代码变得复杂和难以理解,相反,它会使你的代码更加清晰、模块化,易于维护。逐渐将设计模式的思想融入到自己的编程风格中,形成个性化的代码风格。

2、实战演练

学以致用是掌握设计模式的关键。在实际项目中应用设计模式,从而更好地理解其实际应用场景。实战中的经验往往比理论知识更加深刻和有说服力。

3、逐步演进

不要急于一时,逐步演进是掌握设计模式的关键。从一段已有的代码开始,尝试用设计模式和SOLID原则进行重构。通过对比前后的代码,你将会发现自己在设计和编写代码方面的进步。

4、重点理解设计原则

设计模式的基石是设计原则,例如开放封闭原则、单一职责原则等。深入理解这些原则,能够更好地指导你在实际项目中的设计和编码过程。设计原则是设计模式的根基,也是培养良好代码习惯的关键。

三、设计原则的补充说明

一般的书籍和文章讲到设计原则,都讲的是 SOLID 原则,而我这里要说的是七原则:SOLID + CARP + LoD

1 、SRP(Single responsibility Principle)单一职责原则

SRP 是一项简单易懂且重要的原则,但是在实际过程中往往最容易忽略的,它强调在应用中,一个类应该只有一个引起变化的原因,只有一个职责。

SRP 是基于康威定律的推导结论:软件系统的最佳结构高度依赖于开发这个系统的组织的内部结构,每个软件模块都有且只有一个需要被改变的理由。

优点
  • 降低类之间的耦合:将不同职责分解为不同的类,降低类之间的依赖关系,提高系统的灵活性和可维护性
  • 提升类的可维护性和可重用性:当一个类只有一个职责时,修改该职责不会影响到其他职责,使得类更加稳定,易于维护和重用
  • 简化设计过程:SRP 原则使得类的设计更加清晰,每个类都专注于解决一个问题,降低了设计的复杂性
示例代码

多职责的类设计

public class UserService {
    /*** 运营部员工绩效计算 */
    public BigDecimal calculateKPIResultForOperation() { }
    
    /*** 商务员工绩效计算 */
    public BigDecimal calculateKPIResultForBusiness() { }
    
    /*** 产品部员工绩效计算 */
    public BigDecimal calculateKPIResultForProduct() { }
    
    /*** 技术部员工绩效计算 */
    public BigDecimal calculateKPIResultForTechnology() { }
}

SRP 后的类设计

public interface UserService {
    public BigDecimal calculateKPIResult();
}

// 不同部门实现接口
public class OperationUserService implement UserService {}
public class BusinessUserService implement UserService {}
public class ProductUserService implement UserService {}
public class TechnologyUserService implement UserService {}
注意点
  • 拆分多职责类:如果一个类承担了多个职责,就一定要拆分为多个类,确保每个类只有一个职责
  • 识别变化原因:识别引起类变化的原因,然后职责分配到对应的类,确保每个类的变化原因是明确的
  • 避免过度设计:尽可能简单,避免过度设计和复杂性,SRP 的目标是简化设计,而不是增加不必要的结构

2 、OCP(Open/Close Principle) 开闭原则

OCP 的核心思想是通过扩展已有的代码,增加新的行为和功能,而不是修改已有的代码。

优点
  • 提高代码的可维护性和可重用性:允许系统通过扩展已有的代码来应对新的需求,而不是修改已有的代码,降低引入错误的风险
  • 减少代码的耦合度:模块化的设计使得系统个部分之间的耦合度降低,一个模块的修改不会对其他模块产生影响
  • 提高系统的可扩展性和可升级性:新功能可以通过添加新的类或模块来实现,而不是修改已有的代码,使得系统更容易扩展和升级
示例代码

无 OCP 的代码

public class Calculator {  
    public int add(int a, int b) {  
        return a + b;  
    }  
      
    public int subtract(int a, int b) {  
        return a - b;  
    }  
      
    public int multiply(int a, int b) {  
        return a * b;  
    }  
      
    public int divide(int a, int b) {  
        return a / b;  
    }  
}

有 OCP 的代码

public interface Operation {  
    int calculate(int a, int b);  
}  
  
public class AddOperation implements Operation {  
    public int calculate(int a, int b) {  
        return a + b;  
    }  
}  
  
public class SubtractOperation implements Operation {  
    public int calculate(int a, int b) {  
        return a - b;  
    }  
}  
  
public class MultiplyOperation implements Operation {  
    public int calculate(int a, int b) {  
        return a * b;  
    }  
}  
  
public class DivideOperation implements Operation {  
    public int calculate(int a, int b) {  
        return a / b;  
    }  
}
注意点
  • 使用 OCP 原则:把实体设计成可扩展,通过新加类、模块或者函数来扩展功能和行为
  • 抽象化已有代码:对已有代码进行抽象,将具体的实现细节封装,对外仅提供抽象的接口
  • 避免过度设计:OCP 原则的目标是简化设计而不是增加不必要的结构

3 、LSP(Liskov Substitution Principle)里氏替换原则

LSP 强调在软件中,子类必须能够替换其父类,即子类应该具有与父类相同的行为和功能,而不仅仅是继承父类的属性和方法。

优点
  • 提高代码的可读性和可维护性:子类与父类具有一致的行为和功能,使得代码更易于理解和维护
  • 减少代码的冗余和复杂性:子类继承父类的方法和属性,可以避免重复编写相似的代码
  • 提高系统的可扩展性和可升级性:新的子类可以无缝地替换父类,不会影响系统的其他部分
示例代码

无 LSP 代码

class Shape {  
    void draw() {  
        System.out.println("Drawing a shape");  
    }  
}  
  
class Circle extends Shape {  
    void draw() {  
        System.out.println("Drawing a circle");  
    }  
}

有 LSP 代码

interface Drawable {  
    void draw();  
}  
   
class Shape implements Drawable {  
    public void draw() {  
        System.out.println( "Drawing a shape");  
    }  
}  
  
class Circle extends Shape {  
    public void draw() {  
        System.out.println("Drawing a circle");  
    }  
} 
注意点
  • 子类具有一致的行为和功能:子类必须具有与父类相同的行为和功能,但不能改变父类的行为和功能
  • 抽象类定义抽象方法:抽象类应该定义抽象方法,具体方法在子类中实现
  • 避免继承滥用:避免使用继承来共享行为,继承是用来实现多态行为的,而不是为了代码的重用。如果子类需要不同的功能和行为,那应该通过重写父类方法来实现

4 、ISP(Interface Segregation Principle)接口隔离原则

ISP 强调在应用中使用多个特定的接口,而不是一个单一的总接口,从而避免端侧就不需要被强制依赖他们不需要的接口。

优点
  • 提高代码的可维护性和可重用性,特定接口提供特定服务,代码可以更加模块化和可定制化
  • 减少端侧的复杂性,端侧只需要依赖实际使用的接口,避免对不相关接口的强制依赖
  • 提高系统的可扩展性和可升级性,新的接口可以被添加而不会影响实际使用的接口,使得系统更容易扩展和升级
示例代码

无 ISP 代码

interface ShoppingCart {  
    void addItem(Product product, int quantity);  
    void removeItem(Product product);  
    void updateQuantity(Product product, int quantity);  
}  
  
class ShoppingCartImpl implements ShoppingCart {  
    private Map<Product, Integer> items = new HashMap<>();  
      
    @Override  
    public void addItem(Product product, int quantity) {  
        items.put(product, quantity);  
    }  
      
    @Override  
    public void removeItem(Product product) {  
        items.remove(product);  
    }  
      
    @Override  
    public void updateQuantity(Product product, int quantity) {  
        int currentQuantity = items.get(product);  
        items.put(product, currentQuantity + quantity);  
    }  
}

有 ISP 代码

interface AddToCart {  
    void addItem(Product product, int quantity);  
}  
  
interface RemoveFromCart {  
    void removeItem(Product product);  
}  
  
interface UpdateQuantity {  
    void updateQuantity(Product product, int quantity);  
}  
  
class ShoppingCartImpl implements AddToCart, RemoveFromCart, UpdateQuantity {  
    private Map<Product, Integer> items = new HashMap<>();  
      
    @Override  
    public void addItem(Product product, int quantity) {  
        items.put(product, quantity);  
    }  
      
    @Override  
    public void removeItem(Product product) {  
        items.remove(product);  
    }  
      
    @Override  
    public void updateQuantity(Product product, int quantity) {  
        int currentQuantity = items.get(product);  
        items.put(product, currentQuantity + quantity);  
    }  
}
注意点
  • 接口定义尽可能小:每个接口提供有限的服务,方法尽可能少,不要妄想一个接口走遍天下
  • 分离不相关功能:如果接口中提供的功能不相关,需要将接口进行分离操作,形成独立接口,代码可更模块化和可定制化
  • 避免使用过大的总接口:总接口应该根据需要提供适当的功能,而不是一刀切提供所有功能

5 、DIP(Dependency Inversion Principle)依赖倒置原则

DIP 强调在应用中,高层模块不应该依赖于底层模块,它们应该依赖于抽象。

优点
  • 提高代码的可读性和可维护性:高层模块依赖于抽象,而不是具体实现,使得代码更灵活和易于理解
  • 降低类之间的耦合度:依赖抽象不依赖具体实现,减少了高层模块和底层模块之间的直接依赖,提高了系统的灵活性
  • 提高系统的可扩展性和可升级性:新的实现可以通过实现抽象来引入,不需要修改高层模块的代码
示例代码

无 DIP 代码

class UserService {  
    private UserDao userDao;  
      
    public UserService(UserDao userDao) {  
        this.userDao = userDao;  
    }  
      
    public User getUserById(int userId) {  
        return userDao.getUserById(userId);  
    }  
}  
  
class UserDao {  
    public User getUserById(int userId) {  
        // 具体实现逻辑,如从数据库中获取用户信息  
        return new User(userId, "John Doe");  
    }  
}

有 DIP 代码

interface UserDataAccess {  
    User getUserById(int userId);  
}  
  
class UserDao implements UserDataAccess {  
    @Override  
    public User getUserById(int userId) {  
        // 具体实现逻辑,如从数据库中获取用户信息  
        return new User(userId, "John Doe");  
    }  
}  
  
class UserService {  
    private UserDataAccess userDataAccess;  
      
    public UserService(UserDataAccess userDataAccess) {  
        this.userDataAccess = userDataAccess;  
    }  
      
    public User getUserById(int userId) {  
        return userDataAccess.getUserById(userId);  
    }  
}
注意点
  • 通过接口或抽象类定义依赖关系:使用接口或抽象类来定义高层模块和底层模块之间的依赖关系
  • 避免直接依赖具体类:如果直接依赖具体类,一旦有修改,依赖元就要同步改动,影响和成本都较高
  • 使用依赖注入解耦:使用依赖注入来解耦类之间的依赖关系,通过注入抽象的实现来实现高层模块对底层模块的依赖

6 、CARP(Composition/Aggregation Reuse Principle)合成/聚合复用原则

CARP 强调在应用设计过程中优先使用合成/聚合的关系,而不是继承的关系来实现复用。

优点
  • 更好地代码封装:通过使用合成/聚合,可以将对象的不同部分封装在不同的类中,更好地隐藏细节,提高代码的模块化和可维护性
  • 更灵活的代码结构:通过使用合成/聚合,可以更容易地改变对象的行为和结构,只需要修改相关的类,不需要修改整个继承体系
  • 更好的可重用性:通过使用合成/聚合,可以根据需要组合不同的对象来实现代码的可重用性,且合成/聚合本身是一种松耦合,可以更便捷地组装新的对象类型
  • 更好的可扩展性:通过使用合成/聚合,更便捷地添加新的功能和行为到应用中,这种灵活的关系,可以更容易适应新的需求和变化
示例代码

无 CARP 代码

class Car {  
    private Engine engine;  
    private Transmission transmission;  
    private Wheel wheel;  
    private Door door;  
  
    public Car(Engine engine, Transmission transmission, Wheel wheel, Door door) {  
        this.engine = engine;  
        this.transmission = transmission;  
        this.wheel = wheel;  
        this.door = door;  
    }  
  
    public void start() {  
        engine.start();  
    }  
  
    public void shift(int gear) {  
        transmission.shift(gear);  
    }  
  
    public void turn(int degrees) {  
        wheel.turn(degrees);  
    }  
  
    public void open() {  
        door.open();  
    }  
}

有 CARP 代码

interface Engine {  
    void start();  
}  
interface Transmission {  
    void shift(int gear);  
}  
interface Wheel {  
    // 可以添加一些方法,例如 rotate() 和 brake() 等  
}  
interface Door {  
    void open();  
}  
class Car {  
    private Engine engine;  
    private Transmission transmission;  
    private Wheel wheel;  
    private Door door;  
  
    public Car(Engine engine, Transmission transmission, Wheel wheel, Door door) {  
        this.engine = engine;  
        this.transmission = transmission;  
        this.wheel = wheel;  
        this.door = door;  
    }  
}
注意点
  • 封装变化:将变化的部分封装起来,使得变化对其他部分的影响最小
  • 强调组合/聚合:首选使用组合/聚合关系,而不是直接继承关系,以提高灵活性和可维护性
  • 松耦合:合成/聚合是一种松耦合关系,允许系统更容易地适应变化

7 、LoD(Law of Demeter)迪米特法则

LoD 强调在应用中应该尽量减少对象之间的直接依赖关系,降低耦合度,提高可维护性和可重用性。

核心思想是一个对象对其他对象保持最少的了解,并且只和那些和自己最有直接关系的对象进行交互。

一个对象只暴露必要的接口给其他对象,并且应该通过这些接口与其他对象进行交互。

优点
  • 降低耦合度:减少对象之间的直接依赖关系,使得系统更容易扩展和维护
  • 提高可维护性:对象之间的松耦合关系使得修改一个对象的内部实现不会影响其他对象
  • 提高可重用性:松耦合关系允许对象更容易地被独立重用在不同的上下文中
示例代码

无 LoD 代码

class Account {  
    private User user;  
    private List<Transaction> transactions;  
  
    public Account(User user, List<Transaction> transactions) {  
        this.user = user;  
        this.transactions = transactions;  
    }  
  
    public double getBalance() {  
        double balance = 0.0;  
        for (Transaction transaction : transactions) {  
            balance += transaction.getAmount();  
        }  
        return balance;  
    }  
  
    public void debit(double amount) {  
        user.setBalance(user.getBalance() - amount);  
    }  
}

有 LoD 代码

interface UserService {  
    double getBalance(User user);  
}  
  
interface TransactionService {  
    void debit(User user, double amount);  
}  
  
class Account {  
    private UserService userService;  
    private TransactionService transactionService;  
  
    public Account(UserService userService, TransactionService transactionService) {  
        this.userService = userService;  
        this.transactionService = transactionService;  
    }  
  
    public double getBalance() {  
        return userService.getBalance(userService.getUser());  
    }  
  
    public void debit(double amount) {  
        transactionService.debit(userService.getUser(), amount);  
    }  
}
注意点
  • 定义接口:将对象的相关操作定义在接口中,而不是直接依赖于具体的实现
  • 通过接口交互:对象应该通过接口进行交互,而不是直接调用其他对象的方法
  • 减少依赖关系:一个对象应该只与其直接的朋友发生交互,避免依赖过多的对象

接下来会逐一介绍各个设计模式。

我在介绍每一个设计模式的时候都会采用统一的框架,如下:

1、什么是 XXX 设计模式?

2、为什么使用 XXX 设计模式?

3、如何实现 XXX 设计模式?

4、是否存在缺陷和不足?

5、如何缓解缺陷和不足?

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVM对象创建与内存分配机制分析

对象的创建 对象创建的主要流程: 1.类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类加…

易基因:动脉粥样硬化中的DNA甲基化和组蛋白修饰及其表观遗传治疗视角|综述

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 动脉粥样硬化&#xff08;Atherosclerosis, as&#xff09;是一种以动脉血管壁炎症和斑块积聚为特征的血管病变&#xff0c;是大多数心血管疾病的重要病因。除了脂质沉积和慢性炎症外&am…

Python开发工具PyCharm v2023.3全新发布——全面推出AI Assistant工具

JetBrains PyCharm是一种Python IDE&#xff0c;其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外&#xff0c;该IDE提供了一些高级功能&#xff0c;以用于Django框架下的专业Web开发。 PyCharm v2023.3正式版下载 在 PyCharm 2023.3 中&#xff0c;每…

1-3算法基础-标准模板库STL

1.pair pair用于存储两个不同类型的值&#xff08;元素&#xff09;作为一个单元。它通常用于将两个值捆绑在一起&#xff0c;以便一起传递或返回。 #include <iostream> #include <utility> using namespace std; int main() {pair<int, string> person m…

速卖通(AliExpress)店铺流量怎么转化?自养号测评策略

随着全球电商的蓬勃发展&#xff0c;速卖通&#xff08;AliExpress&#xff09;作为中国领先的跨境电商平台&#xff0c;为卖家提供了一个广阔的销售舞台。然而&#xff0c;对于卖家来说&#xff0c;如何让速卖通店铺实现转化&#xff0c;吸引更多的买家成为关键。 一、速卖通…

PADS的使用

目录 一、PADS常规操作1.1 常用快捷键1.2 Logic相关设置 二、Logic库操作2.1 逻辑库2.2 封装库2.3 元件库 一、PADS常规操作 PADS安装好了之后&#xff0c;主要使用下面三个软件&#xff1a; Logic&#xff1a;画原理图文件&#xff0c;也可以使用OrCAD导入Router&#xff1a;…

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机的数据分类预测【23年新算法】

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机的数据分类预测【23年新算法】 目录 分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机的数据分类预测【23年新算法】分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现DBO-SVM蜣螂算法优化支持向量机的…

让测试效率起飞的8款浏览器兼容性测试工具,你get了吗?

浏览器的兼容性问题&#xff0c;是指不同浏览器使用内核及所支持的 HTML 等网页语言标准不同&#xff0c;用户客户端的环境不同造成的显示效果不能达到理想效果。 对于用户而言&#xff0c;无论使用哪款浏览器&#xff0c;期望看到的效果是正常的统一的。市面上发布的浏览器版…

什么是代码签名证书

代码签名证书是一种用于验证软件开发者身份并确保软件完整性的数字证书。在如今数字化的世界中&#xff0c;代码签名证书扮演着至关重要的角色。它们不仅为软件开发者提供了一种方式来证明其身份&#xff0c;还有助于保护用户免受恶意软件和未经授权的软件更改的侵害。 首先&am…

maui 调用文心一言开发的聊天APP 3

主要是对代码进行了优化 上一个版本写死了帐号跟密码 &#xff0c;这一个帐本有户可以直接设置对相关的key以及secret如果设置错时&#xff0c;在聊天中也会返回提示。注册帐号时同时也设置了key及secrete升级到了net.8.0导出APK&#xff0c;上一个版本是导出abb.解决了变型问…

动物姿态估计:微调 YOLOv8 姿态模型

动物姿态估计是计算机视觉的一个研究领域&#xff0c;是人工智能的一个子领域&#xff0c;专注于自动检测和分析图像或视频片段中动物的姿势和位置。目标是确定一种或多种动物的身体部位&#xff08;例如头部、四肢和尾巴&#xff09;的空间排列。这项技术具有广泛的应用&#…

一起学习生成式人工智能(四)|用低代码实现人工智能应用

点击蓝字 关注我们 编辑&#xff1a;Alan Wang 排版&#xff1a;Rani Sun 微软 Reactor 为帮助广开发者&#xff0c;技术爱好者&#xff0c;更好的学习 .NET Core, C#, Python&#xff0c;数据科学&#xff0c;机器学习&#xff0c;AI&#xff0c;区块链, IoT 等技术&#xff0…

EasyRecovery(数据恢复软件) 2024中文绿色无需激活版下载

EasyRecovery是一款功能强大且专业的数据恢复软件&#xff0c;软件能够对电脑误删的文件进行恢复&#xff0c;包括格式化硬盘是数据恢复、手机U盘数据恢复等&#xff0c;小编今天给大家带来的是根据官软件解压后直接使用。感兴趣的朋友快来下载使用吧。 EasyRecovery-2024mac最…

Java数据结构篇——实现顺序表的增删查改

文章目录 1.线性表2. 顺序表2.1 顺序表结构2.2 实现顺序表接口2.3 打印顺序表2.2 实现新增元素2.3 实现查找元素2.3 获取pos位置的值2.4 删除元素2.5 获取顺序表的长度2.6 清空顺序表 3.代码在这 1.线性表 定义&#xff1a;线性表是 n 个具有相同特性的数据元素的有序序列。线…

数据库性能优化八大方案

毫不夸张的说咱们后端工程师&#xff0c;无论在哪家公司&#xff0c;呆在哪个团队&#xff0c;做哪个系统&#xff0c;遇到的第一个让人头疼的问题绝对是数据库性能问题。如果我们有一套成熟的方法论&#xff0c;能让大家快速、准确的去选择出合适的优化方案&#xff0c;我相信…

Unity之OpenXR+XR Interaction Toolkit接入Meta Quest3

前言 随着备受期待的Meta Quest 3与今年10月10日发布,这款来自Meta的下一代VR游戏头戴设备承诺将彻底改变您的游戏方式。 Meta Quest 3,玩家只需轻松一触即可在虚拟现实和真实世界之间无缝切换,无需摘下头戴设备进行快速现实检查。 Meta Quest 3最引人注目的特点之一是其能…

【知识积累】深度度量学习综述

原文指路&#xff1a;https://hav4ik.github.io/articles/deep-metric-learning-survey Problem Setting of Supervised Metric Learning 深度度量学习是一组旨在衡量数据样本之间相似性的技术。 Contrastive Approaches 对比方法的主要思想是设计一个损失函数&#xff0c;直…

pytorch中的归一化:BatchNorm、LayerNorm 和 GroupNorm

1 归一化概述 训练深度神经网络是一项具有挑战性的任务。 多年来&#xff0c;研究人员提出了不同的方法来加速和稳定学习过程。 归一化是一种被证明在这方面非常有效的技术。 1.1 为什么要归一化 数据的归一化操作是数据处理的一项基础性工作&#xff0c;在一些实际问题中&am…

六.聚合函数

聚合函数 1.什么是聚合函数1.1AVG和SUM函数1.2MIN和MAX函数1.3COUNT函数 2.GROUP BY2.1基本使用2.2使用多个列分组2.3GROUP BY中使用WITH ROLLUP 3.HAVING3.1基本使用3.2WHERE和HAVING的区别 4.SELECT的执行过程4.1查询的结构4.2SELECT执行顺序4.3SQL执行原理 1.什么是聚合函数…

JOSEF约瑟快速跳闸继电器RXMS1RK216063 DC220V

系列型号 RXMS1 RK 216 437快速跳闸继电器&#xff1b;RXMS1 RK 216 237快速跳闸继电器&#xff1b; RXMS1 RK 216 449快速跳闸继电器&#xff1b;RXMS1 RK 216 249快速跳闸继电器&#xff1b; RXMS1 RK 216 450快速跳闸继电器&#xff1b;RXMS1 RK 216 250快速跳闸继电器&a…