Java设计模式笔记——七大设计原则

news2024/12/24 20:32:03

系列文章目录

第一章 Java 设计模式之七大设计原则


文章目录

  • 系列文章目录
  • 前言
  • 一、单一职责原则
    • 1.案例分析
    • 2.改进
  • 二、开闭原则
    • 1.案例分析
    • 2.改进
  • 三、里氏替换原则
    • 1.案例分析
    • 2.改进
  • 四、依赖倒转原则
  • 五、接口隔离原则
    • 1.案例分析
    • 2.改进
  • 六、合成复用原则
    • 1.案例分析
    • 2.改进
  • 七、迪米特原则
    • 1.案例分析
    • 2.改进
  • 总结


前言

面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计模式中,它们是从许多设计方案中总结出的指导性原则。面向对象设计原则也是我们用于评价一个设计模式的使用效果的重要指标之一,本文就记录了常见7种面向对象设计原则学习笔记。


一、单一职责原则

单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小。单一职责原则定义如下:一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可将它们封装在同一类中。

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离

1.案例分析

针对某客户关系管理系统中客户信息图形统计模块,设计出如下方案:

在这里插入图片描述

public class CustomerDataChart {

    public void getConnetion(){
        System.out.println("数据库连接...");
    }

    public void findCustomers(){
        System.out.println("查询客户信息...");
    }

    public void createChart(){
        System.out.println("创建图表...");
    }

    public void displayChart(){
        System.out.println("展示图表...");
    }
}

问题:CustomerDataChart类承担了太多的职责,既包含与数据库相关的方法,又包含与图表生成和显示相关的方法。如果在其他类中也需要连接数据库或者使用findCustomers()方法查询客户信息,则难以实现代码的重用。无论是修改数据库连接方式还是修改图表显示方式都需要修改该类,它不止一个引起它变化的原因,违背了单一职责原则。因此需要对该类进行拆分,使其满足单一职责原则。

2.改进

在这里插入图片描述
类CustomerDataChart拆分为如下三个类:

  1. DBUtil:负责连接数据库,包含数据库连接方法getConnection();
  2. CustomerDAO:负责操作数据库中的Customer表,包含对Customer表的增删改查等方法,如findCustomers();
  3. CustomerDataChart:负责图表的生成和显示,包含方法createChart()和displayChart()
public class CustomerDataChartImprove {
    private CustomerDao customerDao;
    
    public void createChart() {
        System.out.println("创建图表...");
    }

    public void displayChart() {
        System.out.println("展示图表...");
    }
}

public class CustomerDao {
    private DBUtil dbUtil;

    public void findCustomers() {
        System.out.println("查询客户信息...");
    }
}

public class DBUtil {
    public void getConnetion() {
        System.out.println("数据库连接...");
    }
}

二、开闭原则

开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。其定义如下:开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展

为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在Java、C#等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成。在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。

1.案例分析

某客户关系管理系统中可以显示各种类型的图表,如饼状图和柱状图等,为了支持多种图表显示方式,设计方案如下:

在这里插入图片描述

public class PieChart {
    public void display() {
        System.out.println("画饼状图表...");
    }
}
public class BarChart {
    public void display() {
        System.out.println("画柱状图表...");
    }
}
public class ChartDisplay {
    public void display(String type){
        if("pie".equals(type)){
            PieChart pieChart = new PieChart();
            pieChart.display();
        }else if("bar".equals(type)){
            BarChart barChart = new BarChart();
            barChart.display();
        }
    }
}
public class Client {
    public static void main(String[] args) {
        ChartDisplay chartDisplay = new ChartDisplay();
        chartDisplay.display("pie");
    }
}

问题:在该代码中,如果需要增加一个新的图表类,如折线图LineChart,则需要修改ChartDisplay类的display()方法的源代码,增加新的判断逻辑,违反了开闭原则。

2.改进

由于在ChartDisplay类的display()方法中针对每一个图表类编程,因此增加新的图表类不得不修改源代码。可以通过抽象化的方式对系统进行重构,使之增加新的图表类时无须修改源代码,满足开闭原则。具体做法如下:

  1. 增加一个抽象图表类AbstractChart,将各种具体图表类作为其子类;
  2. ) ChartDisplay类针对抽象图表类进行编程,由客户端来决定使用哪种具体图表;

在这里插入图片描述

public abstract class AbstractChart {
    /**
     * 抽象方法
     */
    public abstract void display();
}
public class BarChart extends AbstractChart {
    @Override
    public void display() {
        System.out.println("画柱状图表...");
    }
}
public class PieChart extends AbstractChart{
    @Override
    public void display() {
        System.out.println("画饼状图表...");
    }
}
public class ChartDisplay {
    private AbstractChart abstractChart;

    public void setAbstractChart(AbstractChart abstractChart) {
        this.abstractChart = abstractChart;
    }

    public void display(){
       abstractChart.display();
    }
}
public class Client {
    public static void main(String[] args) {
        ChartDisplay chartDisplay = new ChartDisplay();
        chartDisplay.setAbstractChart(new BarChart());
        chartDisplay.display();

        chartDisplay.setAbstractChart(new PieChart());
        chartDisplay.display();
    }
}

在这里插入图片描述

三、里氏替换原则

如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有变化,那么类型S是类型T的子类型。这个定义比较拗口且难以理解,因此我们一般使用它的另一个通俗版定义: 里氏替换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象

在使用里氏代换原则时需要注意如下几个问题:

  1. 子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。根据里氏代换原则,为了保证系统的扩展性,在程序中通常使用父类来进行定义,如果一个方法只存在子类中,在父类中不提供相应的声明,则无法在以父类定义的对象中使用该方法。
  2. 我们在运用里氏代换原则时,尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。里氏代换原则是开闭原则的具体实现手段之一。
  3. Java语言中,在编译阶段,Java编译器会检查一个程序是否符合里氏代换原则,这是一个与实现无关的、纯语法意义上的检查,但Java编译器的检查是有局限的。

1.案例分析

某客户关系管理系统中,客户(Customer)可以分为VIP客户(VIPCustomer)和普通客(CommonCustomer)两类,系统需要提供一个发送Email的功能,设计方案如下:

在这里插入图片描述

public class CommonCustomer {
    private String name;
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

public class VIPCustomer {
    private String  name;
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
public class EmailSender {

    public void send(CommonCustomer commonCustomer) {
        System.out.println("发送普通用户邮件...");
    }

    public void send(VIPCustomer vipCustomer) {
        System.out.println("发送Vip用户邮件...");
    }
}

问题:无论是普通客户还是VIP客户,发送邮件的过程都是相同的,也就是说两个send()方法中的代码重复,而且在本系统中还将增加新类型的客户。为了让系统具有更好的扩展性,同时减少代码重复,使用里氏代换原则对其进行重构。

2.改进

在这里插入图片描述

public abstract class Customer {
    protected String name;
    protected String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
public class EmailSender {

    public void send(Customer customer) {
        System.out.println("发送" + customer.getName() + "邮件...");
    }
}
public class Client {
    public static void main(String[] args) {
        Customer customer = new CommonCustomer();
        customer.setName("普通用户");
        EmailSender sender = new EmailSender();
        sender.send(customer);

        customer = new VIPCustomer();
        customer.setName("VIP用户");
        sender.send(customer);

    }
}

在这里插入图片描述

四、依赖倒转原则

如果说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要实现机制之一,它是系统抽象化的具体实现。定义如下: 依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

在引入抽象层后,系统将具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

参照上面开闭原则例子

五、接口隔离原则

接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。

1.案例分析

某客户关系管理系统中,客户数据显示模块设计如下接口,其中方法dataRead()用于从文件中读取数据,方法createChart()用于创建图表,方法displayChart()用于显示图表,方法createReport()用于创建文字报表,方法displayReport()用于显示文字报表。
在这里插入图片描述

public interface CustomerDataDisplay {
    void dataRead();
    void createChart();
    void displayChart();
    void createReport();
    void displayReport();
}
public class ConcreteClass implements CustomerDataDisplay{
    @Override
    public void dataRead() {
        System.out.println("数据读取...");
    }

    @Override
    public void createChart() {
        System.out.println("创建图表...");
    }

    @Override
    public void displayChart() {
        System.out.println("展示图表...");
    }

    @Override
    public void createReport() {
        System.out.println("创建报表...");
    }

    @Override
    public void displayReport() {
        System.out.println("展示报表...");
    }
}

问题:由于在接口CustomerDataDisplay中定义了太多方法,即该接口承担了太多职责,一方面导致该接口的实现类很庞大,在不同的实现类中都不得不实现接口中定义的所有方法,灵活性较差,如果出现大量的空方法,将导致系统中产生大量的无用代码,影响代码质量;另一方面由于客户端针对大接口编程,将在一定程序上破坏程序的封装性,客户端看到了不应该看到的方法,没有为客户端定制接口。因此需要将该接口按照接口隔离原则和单一职责原则进行重构,将其中的一些方法封装在不同的小接口中,确保每一个接口使用起来都较为方便,并都承担某一单一角色,每个接口中只包含一个客户端(如模块或类)所需的方法即可。

2.改进

在这里插入图片描述

public interface DataHanler {
    void dataRead();
}
public interface ChartHandler {
    void createChart();
    void displayChart();
}
public interface ReportHandler {
    void createReport();
    void displayReport();
}
public class ConcreteClassImprove implements DataHanler, ChartHandler {
    @Override
    public void dataRead() {
        System.out.println("数据读取...");
    }

    @Override
    public void createChart() {
        System.out.println("创建图表...");
    }

    @Override
    public void displayChart() {
        System.out.println("展示图表...");
    }
}

在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。

六、合成复用原则

合成复用原则又称为组合/聚合复用原则(Composition/Aggregate Reuse Principle, CARP),其定
义如下:尽量使用对象组合,而不是继承来达到复用的目的。

合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合/聚合关系(关联关系),少用继承。

1.案例分析

某客户关系管理系统中,初期考虑到客户数量不多系统采用MySQL作为数据库,与数据库操作有关的类如CustomerDAO类等都需要连接数据库,连接数据库的方法getConnection()封装在DBUtil类中,由于需要重用DBUtil类的getConnection()方法,设计人员将CustomerDAO作为DBUtil类的子类,设计方案如下:
在这里插入图片描述

public class DBUtil {
    public void getConnection(){
        System.out.println("获取数据库连接...");
    }
}
public class CustomerDao extends DBUtil{
    public void addCustomer(){
        super.getConnection();
        System.out.println("添加用户信息...");
    }
}

问题:随着客户数量的增加,系统决定升级为Oracle数据库,因此需要增加一个新的OracleDBUtil类来连接Oracle数据库,由于在初始设计方案中CustomerDAO和DBUtil之间是继承关系,因此在更换数据库连接方式时需要修改CustomerDAO类的源代码,将CustomerDAO作为OracleDBUtil的子类,这将违反开闭原则。

2.改进

388.png)

public abstract class DBUtil {
    public abstract void getConnection();
}
public class OracleDBUtil extends DBUtil{
    @Override
    public void getConnection() {
        System.out.println("获取oracle数据库连接...");
    }
}
public class CustomerDao  {
    private DBUtil dbUtil;

    public void addCustomer(){
        dbUtil.getConnection();
        System.out.println("添加用户信息...");
    }

    public void setDbUtil(DBUtil dbUtil) {
        this.dbUtil = dbUtil;
    }
}

CustomerDAO和DBUtil之间的关系由继承关系变为关联关系,采用依赖注入的方式将DBUtil对象注入到CustomerDAO中,可以使用构造注入,也可以使用Setter注入。如果需要对DBUtil的功能进行扩展,可以通过其子类来实现,如通过子类OracleDBUtil来连接Oracle数据库。由于CustomerDAO针对DBUtil编程,根据里氏代换原则,DBUtil子类的对象可以覆盖DBUtil对象,只需在CustomerDAO中注入子类对象即可使用子类所扩展的方法。

七、迪米特原则

迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。

如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度。迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。

迪米特法则还有几种定义形式,包括:不要和“陌生人”说话、只与你的直接朋友通信等,在迪米特法则中,对于一个对象,其朋友包括以下几类:

  1. 当前对象本身(this);
  2. 以参数形式传入到当前对象方法中的对象;
  3. 当前对象的成员对象;
  4. 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
  5. 当前对象所创建的对象。

1.案例分析

某客户关系管理系统中,包含很多业务操作窗口,在这些窗口中,某些界面控件之间存在复杂的交互关系,一个控件事件的触发将导致多个其他界面控件产生响应,例如,当一个按钮(Button)被单击时,对应的列表框(List)、组合框(ComboBox)、文本框(TextBox)、文本标签(Label)等都将发生改变,在初始设计方案中,界面控件之间的交互关系可简化为如下所示结构:
在这里插入图片描述

由于界面控件之间的交互关系复杂,导致在该窗口中增加新的界面控件时需要修改与之交互的其他控件的源代码,系统扩展性较差,也不便于增加和删除新控件。

可以通过引入一个专门用于控制界面控件交互的中间类(Mediator)来降低界面控件之间的耦合度。引入中间类之后,界面控件之间不再发生直接引用,而是将请求先转发给中间类,再由中间类来完成对其他控件的调用。当需要增加或删除新的控件时,只需修改中间类即可,无须修改新增控件或已有控件的源代码

2.改进

在这里插入图片描述


总结

设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

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

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

相关文章

PythonWeb Django PostgreSQL创建Web项目(三)

了解Django框架下如何配置数据库链接与创建模型和应用 使用Django创建web项目,首先需要了解生成的项目文件结构,以及对应文件功能用途方可开始web项目页面创建,下方先介绍文件功能,之后再配置数据库连接以及管理创建模型与应用&a…

招生咨询|浙江大学MPA项目2023年招生问答与通知

问:报考浙江大学MPA的基本流程是怎么样的? 答:第一阶段为网上报名与确认。MPA考生须参加全国管理类联考,网上报名时间一般为10月初开始、10月下旬截止,错过网上报名时间后不能补报。确认时间一般为11月上旬&#xff0c…

如何提高软件测试效率 降低开发成本?

1、单元测试以开发人员为主 测试分工需根据测试人员的特点进行,而单元测试应以开发人员为主,以保障每个单元能够完成设计的功能。集成测试也可以以开发人员为主进行。当软件体系结构完成后,独立测试人员应尽量选择比较熟悉相关领域的人员。​…

三、Spring的入门程序

第一个Spring程序 创建新的空工程spring6 设置JDK版本17&#xff0c;编译器版本17 设置IDEA的Maven&#xff1a;关联自己的maven 在空的工程spring6中创建第一个maven模块&#xff1a;spring6-001-first 在pom.xml添加spring context依赖和junit依赖&#xff0c; <?x…

基于轻量级YOLO开发构建中国象棋目标检测识别分析系统

关于棋类相关的项目在我之前的博文里面都有做过&#xff0c;如下&#xff1a;《yolov5s融合SPD-Conv用于提升小目标和低分辨率图像检测性能实践五子棋检测识别》《YOLOV5融合SE注意力机制和SwinTransformer模块开发实践的中国象棋检测识别分析系统》《基于yolov5s实践国际象棋目…

第七章.集成学习(Ensemble Learning)—袋装(bagging),随机森林(Random Forest)

第七章.集成学习 (Ensemble Learning) 7.1 集成学习—袋装(bagging),随机森林(Random Forest) 集成学习就是组合多个学习器&#xff0c;最后得到一个更好的学习器。 1.常见的4种集成学习算法 个体学习器之间不存在强依赖关系&#xff0c;袋装&#xff08;bagging&#xff09;…

智慧厕所智能卫生间系统有哪些功能

南宁北站智能厕所主要功能有哪些&#xff1f;1、卫生间环境空气监测男厕、女厕环境空气监测系统包括对厕所内的温度、湿度、氨气、硫化氢、PM2.5、烟雾等气体数据的实时监测。2、卫生间厕位状态监测系统实时监测厕位内目前的使用状态(有人或无人&#xff09;&#xff0c;数据信…

SQLyog图形化界面工具【超详细讲解】

目录 一、SQLyog 介绍 二、SQLyog 社区版下载 三、SQLyog 安装 1、选择Chinese后点击OK 2、点击“下一步” 3、选择“我接受”后点击“下一步” 4、点击“下一步” 5、修改安装位置&#xff08;尽量不要安装在C盘&#xff09;&#xff0c;点击“安装” 6、安装后点击“…

无线WiFi安全渗透与攻防(三)之Windows扫描wifi和破解WiFi密码

系列文章 无线WiFi安全渗透与攻防(一)之无线安全环境搭建 无线WiFi安全渗透与攻防(二)之打造专属字典 windows下wifi进行扫描和破解 1.wifi扫描 &#xff08;1&#xff09;.软件介绍 WirelessMon是一款无线网络扫描工具&#xff0c;它可以帮助用户扫描附近的无线信号&…

操作系统——14.调度算法的评价指标

这篇文章我们来讲一下算法调度的评价指标&#xff0c;为后面讲调度算法做下铺垫 目录 1.概述 1.CPU的利用率 2.系统吞吐量 3.周转时间 4.等待时间 5.响应时间 6.小结 1.概述 首先&#xff0c;我们来看一下这节内容的大体框架 1.CPU的利用率 由于早期的CPU造价极其昂贵…

1.flink简介与重要概念

Introduction 简介 Apache Flink是一个框架和分布式处理引擎&#xff0c;用于在无界和有界数据流上进行有状态计算。Flink可以运行在常见集群环境如YARN Kubernetes Mesos,内存级别的速度和任意的扩展 Unbounded streams 无界数据流 无界数据流有开始但是没有结束,需要持续不断…

JavaSe第4次笔记

1.转义字符和编程语言无关。 2.斜杠(\)需要转义&#xff0c;反斜杠(/)不需要转义。 3.不能做switch的参数的数据类型&#xff1a;long float double boolean( String可以)。 4.输入的写法&#xff1a;Scanner(回车自动带头文件(import java.util.Scanner;)) Scanner scan …

软件测试(linux命令篇-01文件操作命令)

linux文件篇命令linux系统常用文件操作命令1、查看目录内容及常用参数&#xff1a;ls2、目录切换&#xff1a;cd 3、创建文件&#xff1a;touch 4、创建目录 &#xff1a;mkdir5、 删除文件或目录&#xff1a;rm6、文件或目录的复制&#xff1a;cp7、文件或目录的移动&#xff…

TMS Sphinx crack

TMS Sphinx crack 用于身份访问管理的TMS Sphinx Delphi框架&#xff0c;包括授权和身份验证。 TMS Sphinx允许您为多个应用程序实现单点登录(SSO)&#xff1a;web、本机、移动或机器到机器API通信。它可用于通过登录表单、类似的用户界面和基于服务的身份验证来验证实际用户&a…

如何制作一个自定义的winpe?

winpe制作过程 获取相关资源 https://www.aliyundrive.com/s/MP58JbRsm76 文件存放位置 将压缩包存放在一个全英文目录下了,我这里选择了D:/winpe目录 解压文件 将三个压缩包进行解压到当前目录,如下图所示 创建一个mount目录,并在mount目录下分别创建boot和install目…

C++11:继承

目录 继承的基本概念 继承方式 基类和派生类对象赋值转换/切片 继承中的作用域 派生类的四个成员函数&#xff1a; 构造函数 拷贝构造函数 赋值重载 析构函数 静态成员 继承与友元 多继承 菱形继承 多继承的指针偏移问题 组合 继承的基本概念 继承出现的契机是某一…

Java 多线程 --- 锁的概念和类型划分

Java 多线程 --- 锁的概念和类型划分锁的概念乐观锁与悲观锁公平锁与非公平锁什么是可重入锁独占锁与共享锁轻量级锁和重量级锁自旋锁 (Spinlock)锁的概念 锁可以将多个线程对共享数据的并发访问转换为串行访问, 这样一个共享数据一次只能被一个线程访问, 该线程访问结束后其他…

cocos2dx+lua学习笔记:UIPageView的使用

前言 本篇在讲什么 本篇简单介绍Lua篇cocos2dx中UIPageView的相关内容 仅介绍简单的应用&#xff0c;仅供参考 本篇适合什么 适合初学Cocos2dX的小白 适合想要在Cocos2dx-lua中使用UIPageView的人 本篇需要什么 对Lua语法有简单认知 对Cocos2dx-Lua有简单认知 Cocos2…

Hostease美国Linux主机方案租用推荐

美国Linux主机市场在全球市场上具有显著的优势&#xff0c;这使得美国的主机提供商可以提供高性能、高可靠性和高安全性的主机方案&#xff0c;同时为用户提供广泛的选择和灵活性。这些优势也使得美国成为全球最大的主机市场之一。本文将介绍Hostease的美国Linux主机方案租用推…

22《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》中文分享

​《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》 本人能力有限&#xff0c;如果错误欢迎批评指正。 第五章&#xff1a;Folding and Aggregation Are Cooperative Transitions &#xff08;折叠和聚合是同时进行的&#xff09; -蛋白质折叠的协同作…