设计模式- Java

news/2024/12/5 3:46:07/

工厂模式

通过将对象的创建过程封装到一个工厂类中,使得客户端不需要直接使用 new 去创建对象,而是通过调用工厂方法来获取所需的对象。这样可以降低代码耦合度,并方便后续的扩展和维护。

示例代码

简单工厂模式(不配合策略模式):

java">// 手机顶层接口
public interface Phone {void makeCall(String number);
}// 华为手机实现
public class HuaweiPhone implements Phone {@Overridepublic void makeCall(String number) {System.out.println("Using HuaweiPhone to call: " + number);}
}// 苹果手机实现
public class ApplePhone implements Phone {@Overridepublic void makeCall(String number) {System.out.println("Using ApplePhone to call: " + number);}
}// 工厂类
public class PhoneFactory {public static Phone createPhone(String type) {switch (type) {case "Huawei":return new HuaweiPhone();case "Apple":return new ApplePhone();default:throw new IllegalArgumentException("Unknown phone type: " + type);}}
}// 测试类
public class Main {public static void main(String[] args) {Phone huawei = PhoneFactory.createPhone("Huawei");huawei.makeCall("123456789");Phone apple = PhoneFactory.createPhone("Apple");apple.makeCall("987654321");}
}

工厂模式 + 策略模式

目的:当需要扩展更多设备(如平板)时,可以抽象顶层接口,将工厂类的职责划分得更清晰。

java">// 顶层接口:设备
public interface Device {void start();
}// 手机实现
public class PhoneDevice implements Device {@Overridepublic void start() {System.out.println("Starting Phone...");}
}// 平板实现
public class TabletDevice implements Device {@Overridepublic void start() {System.out.println("Starting Tablet...");}
}// 策略模式:设备工厂接口
public interface DeviceFactory {Device createDevice();
}// 手机工厂实现
public class PhoneFactory implements DeviceFactory {@Overridepublic Device createDevice() {return new PhoneDevice();}
}// 平板工厂实现
public class TabletFactory implements DeviceFactory {@Overridepublic Device createDevice() {return new TabletDevice();}
}// 客户端
public class Main {public static void main(String[] args) {DeviceFactory phoneFactory = new PhoneFactory();Device phone = phoneFactory.createDevice();phone.start();DeviceFactory tabletFactory = new TabletFactory();Device tablet = tabletFactory.createDevice();tablet.start();}
}

配合 Map 的映射关系

当设备种类较多时,可以用 Map 管理工厂类,动态获取:

java">import java.util.HashMap;
import java.util.Map;public class DeviceFactoryRegistry {private static final Map<String, DeviceFactory> factoryMap = new HashMap<>();static {factoryMap.put("Phone", new PhoneFactory());factoryMap.put("Tablet", new TabletFactory());}public static Device getDevice(String type) {DeviceFactory factory = factoryMap.get(type);if (factory == null) {throw new IllegalArgumentException("Unknown device type: " + type);}return factory.createDevice();}
}// 测试类
public class Main {public static void main(String[] args) {Device phone = DeviceFactoryRegistry.getDevice("Phone");phone.start();Device tablet = DeviceFactoryRegistry.getDevice("Tablet");tablet.start();}
}
结论

通过引入工厂模式和策略模式的结合,可以让代码更加灵活、可扩展,特别适用于需要动态创建不同类型对象的场景。

装饰器模式

  1. 目的:在不修改原有类的情况下,动态地增强类的功能。
  2. 前提:被增强的类需要有一个顶层的抽象接口。
  3. 实现:通过实现相同接口的装饰器类,将被增强的类作为成员变量进行组合(而不是继承),然后对其方法进行增强或扩展。
示例代码
核心结构
  1. 顶层接口:定义核心功能。
  2. 具体实现类:实现核心功能。
  3. 装饰器类:实现顶层接口,并将被装饰类作为成员变量,通过组合的方式增强功能。
代码实现
java">// 顶层接口
public interface Component {void operation();
}// 具体实现类
public class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent: 原本的功能");}
}// 装饰器基类
public abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}// 第一个具体装饰器
public class DecoratorA extends Decorator {public DecoratorA(Component component) {super(component);}@Overridepublic void operation() {super.operation();addFunctionalityA();}private void addFunctionalityA() {System.out.println("DecoratorA: 增强功能 A");}
}// 第二个具体装饰器
public class DecoratorB extends Decorator {public DecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation();addFunctionalityB();}private void addFunctionalityB() {System.out.println("DecoratorB: 增强功能 B");}
}// 测试类
public class Main {public static void main(String[] args) {// 原始组件Component component = new ConcreteComponent();// 增强功能 AComponent decoratorA = new DecoratorA(component);decoratorA.operation();System.out.println("----------");// 增强功能 A + BComponent decoratorB = new DecoratorB(decoratorA);decoratorB.operation();}
}
输出结果
ConcreteComponent: 原本的功能
DecoratorA: 增强功能 A
----------
ConcreteComponent: 原本的功能
DecoratorA: 增强功能 A
DecoratorB: 增强功能 B

装饰器模式的优点
  1. 开闭原则:在不修改原类的情况下,对功能进行扩展。
  2. 灵活性:可以动态组合多个装饰器,叠加增强功能。
  3. 替代继承:相比于直接继承扩展类功能,装饰器更灵活,不会导致类爆炸问题。
装饰器模式的缺点
  1. 复杂性:对于过多的装饰器,代码结构可能变得复杂。
  2. 性能开销:每一层装饰器都会增加额外的调用栈。

适配器模式

  1. 目标:使得不兼容的接口可以协同工作,适配器模式让一个类的接口变得与客户端期望的接口兼容。
  2. 工作原理:适配器类通过组合的方式持有旧接口对象,并通过重写方法来实现对旧接口的适配,让它能够符合新的接口要求。
  3. 典型场景:当你有一个过时的接口或第三方库,无法直接使用,但是你又不想修改旧的代码,适配器模式就非常适合。
示例代码

假设我们有一个音乐播放器,旧版本只支持 MP3 格式,而新版本支持 MP4 格式。我们可以使用适配器模式来将旧播放器适配到新的播放器接口。

1. 定义接口
  • 新播放器接口:定义新版本播放器支持的播放方法。
  • 旧播放器接口:定义老版本播放器支持的播放方法。
java">// 新播放器接口
public interface NewPlayer {void playMP4(String fileName);
}// 旧播放器接口
public interface OldPlayer {void playMP3(String fileName);
}
2. 旧播放器实现

旧播放器只能播放 MP3 格式。

java">// 旧的播放器实现
public class OldMP3Player implements OldPlayer {@Overridepublic void playMP3(String fileName) {System.out.println("Playing MP3 file: " + fileName);}
}
3. 新播放器实现

新播放器支持 MP4 格式。

java">// 新的播放器实现
public class NewMP4Player implements NewPlayer {@Overridepublic void playMP4(String fileName) {System.out.println("Playing MP4 file: " + fileName);}
}
4. 适配器类

适配器将旧播放器的 playMP3 方法适配为新播放器的 playMP4 方法。

java">// 适配器类:将旧播放器适配为新播放器
public class AdapterPlayer implements NewPlayer {private OldPlayer oldPlayer;public AdapterPlayer(OldPlayer oldPlayer) {this.oldPlayer = oldPlayer;}@Overridepublic void playMP4(String fileName) {// 当遇到 MP3 格式时,调用旧播放器播放System.out.println("Adapting to MP4 format, using old player to play MP3...");oldPlayer.playMP3(fileName);}
}
5. 客户端使用

在客户端使用时,可以通过适配器类使得旧播放器也能兼容新播放器的接口。

java">public class Main {public static void main(String[] args) {OldPlayer oldPlayer = new OldMP3Player();NewPlayer adapterPlayer = new AdapterPlayer(oldPlayer);// 通过适配器调用新播放器的接口adapterPlayer.playMP4("song.mp3");}
}
输出结果
Adapting to MP4 format, using old player to play MP3...
Playing MP3 file: song.mp3
适配器模式的优点
  1. 兼容性:适配器模式能够使得旧系统与新系统之间保持兼容,避免修改旧代码。
  2. 灵活性:适配器类可以根据不同的需求来适配多个接口,增加了系统的灵活性。
  3. 单一职责:适配器专门用于接口的转换,符合单一职责原则。
适配器模式的缺点
  1. 增加了代码复杂度:每个适配器类都会增加代码量,可能会增加维护的复杂性。
  2. 可能需要大量的适配器:如果需要适配的接口很多,适配器类的数量可能会增加,导致类的管理变得更加复杂。

组合模式

  1. 统一接口:通过定义一个顶层接口,使得客户端可以通过相同的方式来处理单个对象和组合对象(容器对象)。
  2. 递归结构:对象可以包含子对象,这样形成一个树形结构,允许递归组合。
  3. 灵活性:通过组合树中的节点(例如,单个区域或区域列表),可以灵活地构建复杂结构。
组合模式的应用场景
  • 组织结构:例如公司组织结构,其中有公司、部门、员工等组成部分。
  • 文件系统:文件夹中包含文件,文件夹也可以包含文件夹,形成递归的树形结构。
  • 图形绘制:多个图形可以组合成一个复合图形,例如矩形、圆形等基本图形可以组合成更复杂的图形。
示例代码

假设你要统计中国各个省市的人口数量,可以使用组合模式来表示不同层级的区域(省、市等)并进行统计。

1. 定义顶层接口
java">// 区域接口,所有的区域类(省、市等)都需要实现这个接口
public interface Region {int getPopulation();  // 获取该区域的人口数
}
2. 具体实现类(叶子节点)

每个区域的具体实现类,如省或者市,都实现 Region 接口,并计算其人口数。

java">// 省级区域,叶子节点
public class Province implements Region {private String name;private int population;public Province(String name, int population) {this.name = name;this.population = population;}@Overridepublic int getPopulation() {System.out.println("统计 " + name + " 的人口: " + population);return population;}
}// 市级区域,叶子节点
public class City implements Region {private String name;private int population;public City(String name, int population) {this.name = name;this.population = population;}@Overridepublic int getPopulation() {System.out.println("统计 " + name + " 的人口: " + population);return population;}
}
3. 组合类(容器节点)

组合类可以包含多个 Region 对象,无论是单独的 Province 还是包含多个市的 RegionGroup

java">// 区域组,组合节点
import java.util.List;public class RegionGroup implements Region {private String name;private List<Region> subRegions;public RegionGroup(String name, List<Region> subRegions) {this.name = name;this.subRegions = subRegions;}@Overridepublic int getPopulation() {int totalPopulation = 0;System.out.println("统计 " + name + " 的人口总数:");for (Region region : subRegions) {totalPopulation += region.getPopulation();}return totalPopulation;}
}
4. 客户端使用

通过组合 RegionGroupRegion,可以灵活地统计不同区域的人口。

java">import java.util.Arrays;public class Main {public static void main(String[] args) {// 创建市级区域Region changsha = new City("长沙市", 1000);Region zhuzhou = new City("株洲市", 800);// 创建省级区域Region hunan = new Province("湖南省", 10000);// 创建包含多个市的区域组合Region cityGroup = new RegionGroup("湖南省", Arrays.asList(changsha, zhuzhou));// 再创建包含省和市的更大组合Region country = new RegionGroup("中国", Arrays.asList(hunan, cityGroup));// 获取中国的总人口int totalPopulation = country.getPopulation();System.out.println("中国总人口:" + totalPopulation);}
}
组合模式的优点
  1. 简化客户端代码:客户端可以通过统一的 Region 接口来处理单个对象和组合对象,简化了代码的复杂性。
  2. 灵活扩展:可以方便地添加新的 Region 类型(如城市、地区等),而不需要修改现有的代码。
  3. 支持递归结构:组合模式使得树形结构的递归实现变得容易,适合表示具有层次结构的对象。
组合模式的缺点
  1. 增加了系统复杂性:由于组合结构的递归特性,如果层次结构复杂,系统的复杂度会增加。
  2. 不适合所有场景:如果对象之间没有明显的层级结构,组合模式可能会使得设计变得不必要复杂。

代理模式

  1. 代理角色:代理类代表另一个对象,并控制对该对象的访问。客户端与代理类交互,而不直接与目标对象(真实对象)交互。
  2. 真实角色:目标对象,执行实际的业务逻辑。
  3. 代理类型:
    • 静态代理:代理类在编译时就已经存在,代理类和目标类之间的关系是静态的。
    • 动态代理:代理类在运行时动态生成,通常通过反射机制创建,目标类和代理类的关系是动态的。
代理模式的常见应用场景
  • 延迟加载:代理可以在需要时再创建真实对象,避免不必要的资源消耗。
  • 权限控制:代理可以控制对目标对象的访问,确保只有经过授权的操作才能执行。
  • 日志记录、性能监控:代理可以在调用目标对象之前或之后添加日志记录、性能监控等功能。
  • 远程代理:在分布式系统中,代理可以用来代表远程对象,隐藏远程调用的细节。
示例代码

下面是一个简单的静态代理模式的示例:

1. 定义接口
java">// 接口,真实角色和代理角色都实现这个接口
public interface Subject {void request();
}
2. 真实角色
java">// 真实角色
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: 执行请求");}
}
3. 代理角色
java">// 代理角色
public class ProxySubject implements Subject {private RealSubject realSubject;@Overridepublic void request() {// 在代理角色中加入额外的操作,例如权限验证、日志记录等if (realSubject == null) {realSubject = new RealSubject();}System.out.println("ProxySubject: 代理前的操作");realSubject.request();  // 调用真实角色的方法System.out.println("ProxySubject: 代理后的操作");}
}
4. 客户端代码
java">public class Client {public static void main(String[] args) {Subject proxy = new ProxySubject();  // 创建代理对象proxy.request();  // 通过代理对象调用请求}
}
输出结果
ProxySubject: 代理前的操作
RealSubject: 执行请求
ProxySubject: 代理后的操作
代理模式的优点
  1. 控制访问:代理对象可以控制对真实对象的访问,增加安全性和权限控制。
  2. 增加功能:代理类可以在不修改真实对象的前提下,增加额外的功能(如日志记录、事务处理等)。
  3. 延迟初始化:通过代理模式,可以在实际需要的时候再创建真实对象,节省资源。
  4. 透明性:代理模式使得客户端代码与真实对象的交互保持一致,客户端不需要关心代理对象的存在。
代理模式的缺点
  1. 增加系统复杂度:代理模式需要创建额外的代理对象,可能会增加系统的复杂性。
  2. 性能开销:由于代理对象在方法调用前后可能添加了额外的处理逻辑,可能会带来性能开销。

责任链模式

  1. 链条结构:多个处理对象(处理者)形成一个链条,每个处理对象处理某个特定的请求或任务。
  2. 职责划分:每个处理对象只负责自己特定的任务,且每个对象都知道下一个处理对象是哪个。
  3. 请求传递:请求从链头开始,依次传递给链中的各个处理对象,每个对象可以选择处理请求或将请求传递给链中的下一个对象。
  4. 解耦:客户端无需知道请求将被哪个处理对象处理,只需要将请求发送到链的开始,其他的交给链中的处理对象。
责任链模式的应用场景
  • 日志处理:日志记录时可以通过不同的处理器(如输出到文件、数据库、控制台等)依次传递。
  • 权限验证:请求可以在多个权限验证处理器之间传递,直到找到合适的处理器进行处理。
  • 事件处理:UI 事件的处理,事件可以通过不同的事件处理器(如按钮点击、输入框变化等)传递。
示例代码

以下是责任链模式的简单实现:

1. 定义处理者接口
java">// 处理者接口,每个处理者处理某个请求,或者将请求传递给下一个处理者
public interface Handler {void setNextHandler(Handler nextHandler);  // 设置下一个处理者void handleRequest(String request);  // 处理请求
}
2. 具体处理者实现
java">// 处理者 A
public class HandlerA implements Handler {private Handler nextHandler;@Overridepublic void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if (request.equals("TaskA")) {System.out.println("HandlerA is handling the request.");} else if (nextHandler != null) {nextHandler.handleRequest(request);  // 传递给下一个处理者} else {System.out.println("No handler can handle the request.");}}
}// 处理者 B
public class HandlerB implements Handler {private Handler nextHandler;@Overridepublic void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if (request.equals("TaskB")) {System.out.println("HandlerB is handling the request.");} else if (nextHandler != null) {nextHandler.handleRequest(request);  // 传递给下一个处理者} else {System.out.println("No handler can handle the request.");}}
}
3. 客户端使用
java">public class Main {public static void main(String[] args) {// 创建处理者Handler handlerA = new HandlerA();Handler handlerB = new HandlerB();// 设置责任链handlerA.setNextHandler(handlerB);// 客户端请求System.out.println("Requesting TaskA:");handlerA.handleRequest("TaskA");System.out.println("\nRequesting TaskB:");handlerA.handleRequest("TaskB");System.out.println("\nRequesting TaskC:");handlerA.handleRequest("TaskC");}
}
输出结果
Requesting TaskA:
HandlerA is handling the request.Requesting TaskB:
HandlerB is handling the request.Requesting TaskC:
No handler can handle the request.
责任链模式的优点
  1. 解耦:客户端不需要知道具体的处理者,只需要发送请求,链条中的处理者会依次处理请求。这降低了客户端与具体处理者之间的耦合。
  2. 动态处理:可以动态地改变链条的处理顺序,增加或移除处理者非常方便。
  3. 扩展性:可以通过添加新的处理者来扩展功能,符合开闭原则。
责任链模式的缺点
  1. 性能问题:如果链条过长,或者每个处理者的处理逻辑较复杂,可能会影响性能,因为请求会经过多次处理。
  2. 调试困难:链条结构可能导致请求在链中传递,调试时难以跟踪请求的流向。
总结

责任链模式通过将多个处理对象连接成一个链条,让请求在链中传递,直到某个处理对象能够处理它为止。每个处理对象可以选择处理请求或将请求转发给下一个处理对象。这种模式不仅解耦了请求的发送者与处理者,还提供了灵活的扩展机制。

建造者模式

没错,建造者模式(Builder Pattern)确实和链式调用(Fluent Interface)有很大的相似之处。它的核心思想就是将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。

通过链式调用的方式,你可以一步步地为对象设置所需的属性,而不必关心对象具体是如何被构建的。建造者模式的优势在于:

  1. 解耦构建过程和表示:建造者模式将对象的构建逻辑与业务逻辑分开,便于维护和扩展。
  2. 链式调用:使代码简洁、直观,调用顺序也更加灵活。
  3. 代码可读性强:通过链式调用可以清晰地了解一个对象的构建过程。

举个简单的例子:

java">// 假设我们构建一个 Computer 对象
public class Computer {private String CPU;private String RAM;private String storage;// 私有构造函数,避免直接创建对象private Computer(Builder builder) {this.CPU = builder.CPU;this.RAM = builder.RAM;this.storage = builder.storage;}public static class Builder {private String CPU;private String RAM;private String storage;public Builder setCPU(String CPU) {this.CPU = CPU;return this;}public Builder setRAM(String RAM) {this.RAM = RAM;return this;}public Builder setStorage(String storage) {this.storage = storage;return this;}public Computer build() {return new Computer(this);}}@Overridepublic String toString() {return "Computer [CPU=" + CPU + ", RAM=" + RAM + ", Storage=" + storage + "]";}
}// 使用示例
public class Main {public static void main(String[] args) {Computer computer = new Computer.Builder().setCPU("Intel i7").setRAM("16GB").setStorage("512GB SSD").build();System.out.println(computer);}
}

模版模式

模版模式就是把通用的方法全都定义在一个抽象的父类,子类去继承他只专注于实现其他功能就行了是吧,比如泡茶,泡牛奶,都有一个公共的过程就是烧水。

抽象父类
java">public abstract class Beverage {// 模版方法,定义流程public final void prepare() {boilWater();brew();pourInCup();addCondiments();}// 通用方法,父类实现private void boilWater() {System.out.println("烧水...");}private void pourInCup() {System.out.println("将饮品倒入杯子...");}// 抽象方法,子类具体实现protected abstract void brew();protected abstract void addCondiments();
}
泡茶子类
java">public class Tea extends Beverage {@Overrideprotected void brew() {System.out.println("泡茶叶...");}@Overrideprotected void addCondiments() {System.out.println("添加柠檬...");}
}
泡牛奶子类
java">public class Milk extends Beverage {@Overrideprotected void brew() {System.out.println("加热牛奶...");}@Overrideprotected void addCondiments() {System.out.println("添加糖...");}
}
使用模版方法
java">public class Main {public static void main(String[] args) {Beverage tea = new Tea();tea.prepare();System.out.println("------");Beverage milk = new Milk();milk.prepare();}
}
输出结果
烧水...
泡茶叶...
将饮品倒入杯子...
添加柠檬...
------
烧水...
加热牛奶...
将饮品倒入杯子...
添加糖...

优点:

  1. 代码复用:通用部分(如烧水、倒入杯子)只需实现一次。
  2. 扩展性好:添加新类型的饮品只需创建新的子类即可。
  3. 灵活性:可以灵活地定义和调整每一步的具体实现。

模版模式适合用于具有固定流程但实现细节可变的场景,非常实用!


http://www.ppmy.cn/news/1552156.html

相关文章

浅谈C#库之DevExpress

一、DevExpress库介绍 DevExpress是一个功能强大、界面美观的UI组件库&#xff0c;广泛应用于桌面应用程序和Web应用程序的开发中。它提供了丰富的控件和工具&#xff0c;帮助开发人员快速构建现代化的用户界面。DevExpress控件库以其功能丰富、应用简便、界面华丽以及方便定制…

Elasticsearch 进阶

核心概念 索引(Index) 一个索引就是一个拥有几分相似特征的文档的集合。比如说&#xff0c;你可以有一个客户数据的索引&#xff0c;另一个产品目录的索引&#xff0c;还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母)&#xff0c;并且当我们要对这个索…

MySQL1.0

1.数据库的三大范式 范式是为了使数据库设计更加合理&#xff0c;规范&#xff0c;减少数据冗余和数据不一致等问题指定的一系列规则。 第一范式&#xff1a;第一范式要求数据表中的每一列都是不可分割的原子数据项。例如&#xff1a;有一个学生信息表&#xff0c;包含 “学生…

java机器学习库

在 Java 中&#xff0c;进行机器学习的库有很多&#xff0c;涵盖了从基础的线性回归、分类问题&#xff0c;到更复杂的深度学习和强化学习的各种应用。以下是一些常用的 Java 机器学习库&#xff1a; 1. Weka 简介: Weka 是一个广泛使用的机器学习库&#xff0c;提供了大量的…

Profinet转EtherNet/IP网关是如何解决西门子S7-1500PLC与AB PLC的通讯问题的

一、 案例背景 在一个工业现场&#xff0c;一端是AB的PLC&#xff0c;IP地址192.168.1.20;另一端西门子是S7-1500系列&#xff0c;IP地址192.168.2.248。AB的PLC内有 B3、N7、F8 三个寄存器文件涉及到通讯&#xff0c;分别对应西门子PLC的M、DB1、DB2三个存储区域。通过捷米特…

《Vue零基础入门教程》第十五课:样式绑定

往期内容 《Vue零基础入门教程》第六课&#xff1a;基本选项 《Vue零基础入门教程》第八课&#xff1a;模板语法 《Vue零基础入门教程》第九课&#xff1a;插值语法细节 《Vue零基础入门教程》第十课&#xff1a;属性绑定指令 《Vue零基础入门教程》第十一课&#xff1a;事…

【NLP】第四章:门控循环单元GRU

四、门控循环单元GRU 建议看本篇时&#xff0c;一定一定要把前面的LSTM先看看&#xff1a;【NLP】第三章&#xff1a;长短期记忆网络LSTM-CSDN博客 ,当你对LSTM的各个方面的细节都清晰了&#xff0c;GRU就是闭眼就会的&#xff0c;就是秒懂的&#xff0c;而且以后你再听到什么…

网络安全从入门到精通 (第二章-4) 后端基础PHP—简介及基本函数-上

1&#xff0c;什么是PHP&#xff1f; PHP&#xff08;超文本预处理器&#xff09;是一种通用开源语言&#xff0c;&#xff08;是动态语言中的一种&#xff0c;动态语言还有ASP&#xff0c;ASPX&#xff0c;JSP&#xff09;。 PHP语法吸收了C语言&#xff0c;JAVA 和Perl的特点…