JAVA进阶技术之十三:Java与设计模式大揭秘
小标题:揭秘 Java 与设计模式:编程路上的 “指南针” 与 “秘籍”
嘿,各位程序猿/媛们!今天咱就来讲讲 Java 与设计模式那些事儿哈,这可都是咱编程路上的“宝藏秘籍”嘞,学会咯,代码档次“嗖”地一下就上去咯,虽说该掉的头发还是会掉哈,但至少咱写代码的时候能更顺溜不是。
一、啥是设计模式
简单来讲啦,设计模式就好比是建筑图纸啦,是前辈们总结出来应付各种软件开发场景的“超实用”套路哦。它能帮咱们把代码写得又优雅、又好维护、还容易扩展嘞,就跟搭积木似的,照着一定的模式搭,稳稳当当又好看,要是瞎拼凑,说不定一阵风过来就散架咯。
二、23 种设计模式大赏
(一)创建型模式
- 单例模式 举例:就拿 Windows 系统的任务管理器来说哈,不管你在系统哪个旮旯调用它,那都是同一个实例啦。在 Java 里呢,就好像咱的数据库连接池啦,全局只要一个实例就行咯,不然资源浪费不说,还容易出乱子哒。
Java 实现代码:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
瞅瞅这代码,构造函数私有咯,外面只能通过 getInstance 方法拿到唯一实例,第一次调用的时候创建,之后就一直返回同一个哒。
- 工厂模式
举例:你去买手机嘛,总不可能自己动手组装零件咯,找个手机工厂就行啦。在代码里呢,创建对象也可以交给工厂类哒,比如说创建不同形状的图形(圆形、矩形),工厂类根据传进去的参数决定返回哪种图形实例咯。
伪代码示例:
// 图形接口
interface Shape {
void draw();
}
// 圆形类实现图形接口
class Circle implements Shape {
@Override
public void draw() {
System.out.println("画个圆");
}
}
// 矩形类实现图形接口
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画个矩形");
}
}
// 图形工厂类
class ShapeFactory {
public Shape getShape(String shapeType) {
if ("circle".equals(shapeType)) {
return new Circle();
} else if ("rectangle".equals(shapeType)) {
return new Rectangle();
}
return null;
}
}
这工厂就像个万能制造机一样啦,你要啥它就给造啥,代码里对象创建的逻辑都放工厂里,以后要修改创建规则的时候,就不用到处翻代码改咯。
- 抽象工厂模式
举例:还是拿手机工厂来讲哈,现在可不单是生产手机咯,还配套生产手机壳、充电器这些配件哒,不同品牌的手机(像苹果、安卓阵营)对应不同风格的配件组合啦。抽象工厂就是把这一系列相关产品的创建封装起来哒。
伪代码(简单示意,复杂点还能分层抽象等):
// 抽象手机产品
interface Phone {
void call();
}
// 抽象手机壳产品
interface PhoneCase {
void protectPhone();
}
// 苹果手机实现
class IPhone implements Phone {
@Override
public void call() {
System.out.println("用苹果手机打电话");
}
}
// 苹果手机壳实现
class IPhoneCase implements PhoneCase {
@Override
public void protectPhone() {
System.out.println("保护苹果手机");
}
}
// 抽象工厂接口
interface ElectronicFactory {
Phone createPhone();
PhoneCase createPhoneCase();
}
// 苹果工厂实现
class AppleFactory implements ElectronicFactory {
@Override
public Phone createPhone() {
return new IPhone();
}
@Override
public PhoneCase createPhoneCase() {
return new IPhoneCase();
}
}
这样一套下来,不同品牌生态的创建逻辑就很清晰啦,以后要扩展新品牌的时候,加个对应工厂类就行,不会影响到其他代码哒。
- 建造者模式
举例:想象一下你去买电脑哈,有各种配置可选,CPU、内存、硬盘、显卡啥的,你跟店员说你的需求,店员就按照你的要求一点点组装起来。在代码里,比如创建一个复杂的 SQL 查询语句,有查询字段、表名、条件、排序这些部分,建造者模式就可以让你一步一步把这个复杂对象构建出来,而不是一次性在构造函数里写一堆参数。
伪代码:
// 电脑产品类
class Computer {
private String cpu;
private String memory;
private String hardDisk;
// 省略 get、set 方法
public static class ComputerBuilder {
private String cpu;
private String memory;
private String hardDisk;
public ComputerBuilder setCpu(String cpu) {
this.cpu = cpu;
return this;
}
public ComputerBuilder setMemory(String memory) {
this.memory = memory;
return this;
}
public ComputerBuilder setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}
public Computer build() {
Computer computer = new Computer();
computer.setCpu(cpu);
computer.setMemory(memory);
computer.setHardDisk(hardDisk);
return computer;
}
}
}
使用的时候就像这样:
Computer computer = new Computer.ComputerBuilder().setCpu("Intel i7").setMemory("16G").setHardDisk("512G SSD").build();
是不是很清晰,想改哪个配置就改哪个,代码易读又好维护。
- 原型模式
举例:好比你要画好多幅类似的画,一幅画完了,其他的就可以照着这个原型复制,然后再修改一些细节就行咯。在 Java 里,有些对象创建成本高,像加载大数据量的配置文件生成的对象,每次都重新创建太浪费资源,就可以用原型模式,先创建一个原型实例,后面需要的时候克隆一份,再按需修改。
Java 示例(简单示意,需实现 Cloneable 接口):
class Prototype implements Cloneable {
private String data;
public Prototype(String data) {
this.data = data;
}
public String getData() {
return data;
}
@Override
protected Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
}
使用时:
try {
Prototype original = new Prototype("初始数据");
Prototype clone = original.clone();
clone.data = "修改后的数据";
System.out.println(original.getData());
System.out.println(clone.getData());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
(二)结构型模式
- 代理模式
举例:你租房找中介嘛,中介就相当于房东的代理啦,你不用直接跟房东扯水电费、房租这些事儿,找中介就行咯。在网络访问里,就好比你访问国外网站,本地代理服务器先帮你去拿数据,再转给你,还能缓存数据,下次访问就快啦。
Java 示例(简单静态代理):
// 抽象主题接口,比如网络访问接口
interface NetworkAccess {
void access(String url);
}
// 真实主题类,真正执行网络访问的
class RealNetworkAccess implements NetworkAccess {
@Override
public void access(String url) {
System.out.println("正在访问:" + url);
}
}
// 代理类
class ProxyNetworkAccess implements NetworkAccess {
private RealNetworkAccess realAccess;
@Override
public void access(String url) {
if (realAccess == null) {
realAccess = new RealNetworkAccess();
}
// 可以加点前置处理,比如权限验证
System.out.println("权限验证通过,准备访问");
realAccess.access(url);
// 后置处理,如缓存数据
System.out.println("访问完成,缓存数据");
}
}
代理类控制对真实对象的访问,还能在前后搞点小动作,增强功能哒。
- 装饰器模式
举例:你买了杯咖啡哈,想加奶、加糖、加奶油,这些配料就是对咖啡的装饰咯。在代码里,比如说给一个文本框组件,你想给它加个边框、背景色,装饰器模式就能动态扩展功能哒。
伪代码:
// 抽象组件接口,类似可视化组件
interface Component {
void display();
}
// 基础文本框组件
class TextBox implements Component {
@Override
public void display() {
System.out.println("显示一个文本框");
}
}
// 装饰器抽象类,实现组件接口,聚合组件
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void display() {
component.display();
}
}
// 具体装饰器,加边框
class BorderDecorator extends Decorator {
public BorderDecorator(Component component) {
super(component);
}
@Override
public void display() {
super.display();
System.out.println("给组件加上边框");
}
}
// 加背景色装饰器
class BackgroundDecorator extends Decorator {
public BackgroundDecorator(Component component) {
super(component);
}
@Override
public void display() {
super.display();
System.out.println("给组件加上背景色");
}
}
通过层层嵌套装饰器,灵活组合功能,文本框想要啥效果就套啥装饰咯。
- 适配器模式
举例:你手机充电器是 Type-C 接口,可手头只有个 USB 线,这时候用个转接头(适配器)就能充上电啦。在代码里,假如老系统有个旧接口方法,新功能要调用,但是参数啥的不匹配,适配器就派上用场,把新参数适配成旧接口能接受的形式哒。
伪代码:
// 旧接口
interface OldInterface {
void oldMethod(int oldParam);
}
// 旧接口实现类
class OldClass implements OldInterface {
@Override
public void oldMethod(int oldParam) {
System.out.println("旧方法执行,参数:" + oldParam);
}
}
// 新接口
interface NewInterface {
void newMethod(String newParam);
}
// 适配器类,实现新接口,适配旧接口
class Adapter implements NewInterface {
private OldInterface oldObject;
public Adapter(OldInterface oldObject) {
this.oldObject = oldObject;
}
@Override
public void newMethod(String newParam) {
int convertedParam = Integer.parseInt(newParam);
oldObject.oldMethod(convertedParam);
}
}
适配器让新旧代码和平共处,协同工作,避免大改老代码哒。
- 桥接模式
举例:就好像不同品牌的汽车(宝马、奔驰)和不同类型的发动机(汽油、电动),汽车品牌和发动机类型可以独立变化,通过桥接模式把它们组合起来。在图形绘制里,有不同形状(圆形、矩形)和不同的绘制颜色(红、绿),形状类和颜色类分开,用桥接模式关联,这样增加新形状或新颜色都很方便,不会互相影响。
伪代码:
// 抽象形状接口
interface Shape {
void draw();
}
// 抽象颜色接口
interface Color {
void applyColor();
}
// 圆形实现形状接口
class Circle implements Shape {
private Color color;
public Circle(Color color) {
this.color = color;
}
@Override
public void draw() {
System.out.print("画个圆形,");
color.applyColor();
}
}
// 红色实现颜色接口
class Red implements Color {
@Override
public void applyColor() {
System.out.println("颜色是红色");
}
}
使用:
Circle circle = new Circle(new Red());
circle.draw();,
这样形状和颜色解耦,各自扩展容易。
- 组合模式
举例:在文件系统里,文件夹可以包含文件和子文件夹,它们在操作上有共性,像显示名称、获取大小等。组合模式就把它们统一成组件,客户端可以用同样的方式处理文件和文件夹,不管是单个文件还是复杂的文件夹结构,代码简洁统一。
伪代码:
// 抽象组件接口
interface Component {
void display();
}
// 文件类实现组件接口
class File implements Component {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println("文件:" + name);
}
}
// 文件夹类实现组件接口,聚合子组件
class Folder implements Component {
private String name;
private List<Component> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(Component component) {
children.add(component);
}
@Override
public void display() {
System.out.println("文件夹:" + name);
for (Component child : children) {
child.display();
}
}
}
- 外观模式
举例:你去电影院看电影,不用操心灯光怎么控制、音响怎么调试、屏幕怎么升降,有个操作员(外观类)帮你一键搞定这些复杂操作,你只需要按个播放键就行咯。在代码里,比如一个电商系统有订单处理、库存管理、物流对接等复杂模块,外观模式提供一个简单统一的接口给客户端调用,隐藏内部复杂逻辑。
伪代码:
// 订单处理类
class OrderProcessor {
public void processOrder() {
System.out.println("处理订单");
}
}
// 库存管理类
class InventoryManager {
public void checkStock() {
System.out.println("检查库存");
}
}
// 物流对接类
class LogisticsConnector {
public void shipGoods() {
System.out.println("发货");
}
}
// 外观类
class ECommerceFacade {
private OrderProcessor orderProcessor;
private InventoryManager inventoryManager;
private LogisticsConnector logisticsConnector;
public ECommerceFacade() {
orderProcessor = new OrderProcessor();
inventoryManager = new InventoryManager();
logisticsConnector = new LogisticsConnector();
}
public void buyProduct() {
orderProcessor.processOrder();
inventoryManager.checkStock();
logisticsConnector.shipGoods();
}
}
- 享元模式
定义:享元模式(Flyweight Pattern)运用共享技术有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似类的开销,从而提高系统资源的利用率。
详细描述:在享元模式中,有一个享元工厂类负责创建和管理享元对象。客户端需要对象时,向工厂请求,工厂首先检查是否已经存在所需对象,如果有则直接返回共享实例,若没有则创建一个新的并存储起来供后续使用。
举例:以游戏开发为例,游戏中有大量的树木、花草等植物对象,它们的外观模型(如纹理、形状)基本相同,只是位置不同。使用享元模式,将植物的外观模型设计为享元对象,由工厂统一管理。当创建新的植物场景时,对于相同外观的植物,只需从工厂获取已有的享元实例,设置不同的位置信息即可,大大节省了内存开销,提升游戏性能。
伪代码示例
// 抽象享元类
abstract class Flyweight {
abstract void operation(int extrinsicState);
}
// 具体享元类
class ConcreteFlyweight extends Flyweight {
@Override
void operation(int extrinsicState) {
System.out.println("具体享元对象执行操作,外部状态:" + extrinsicState);
}
}
// 享元工厂类
class FlyweightFactory {
private final Map<String, Flyweight> flyweights = new HashMap<>();
Flyweight getFlyweight(String key) {
if (!flyweights.containsKey(key)) {
flyweights.put(key, new ConcreteFlyweight());
}
return flyweights.get(key);
}
}
(三)行为型模式
- 观察者模式
举例:你在微博关注了某个大 V,大 V 一发新动态,你作为粉丝(观察者)就能收到通知咯。在程序里,比如说电商系统,商品价格变了,关注这个商品的用户(观察者)就得收到消息,好决定买不买哒。
伪代码:
// 抽象观察者接口
interface Observer {
void update(String message);
}
// 具体观察者,用户类实现
class User implements Observer {
private String name;
public User(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("用户名不能为空");
}
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "收到消息:" + message);
}
}
// 抽象主题接口,被观察对象接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
// 具体主题,商品类实现
class Product implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
主题对象管理观察者,状态一变就通知大伙,松耦合,扩展观察者超容易哒。
- 策略模式
举例:出行导航,你可以选开车、公交、步行等不同出行策略,导航软件根据你选的策略规划路线咯。在代码里,比如说电商促销,有满减、折扣、赠品等不同促销策略,订单计算价格时按选定策略算哒。
伪代码:
// 抽象策略接口
interface PromotionStrategy {
double calculateDiscount(double price);
}
// 满减策略实现
class FullReductionStrategy implements PromotionStrategy {
@Override
public double calculateDiscount(double price) {
if (price >= 200) {
return price - 50;
}
return price;
}
}
// 折扣策略实现
class DiscountStrategy implements PromotionStrategy {
@Override
public double calculateDiscount(double price) {
return price * 0.8;
}
}
// 上下文类,用策略
class OrderContext {
private PromotionStrategy strategy;
public OrderContext(PromotionStrategy strategy) {
this.strategy = strategy;
}
public double calculateFinalPrice(double price) {
return strategy.calculateDiscount(price);
}
}
这样电商系统在搞促销活动的时候,只需要切换不同的策略实现类给到 OrderContext 就行咯,新增促销玩法也不影响其他老代码,维护起来轻松得很嘞。
- 模板方法模式
举例:就像冲咖啡哈,步骤基本固定的:烧水、磨豆、冲泡、加奶加糖(可选)。模板方法模式就是把这通用流程定义在抽象父类,可变步骤延迟到子类去实现,像美式咖啡不加奶糖,拿铁就要加。
伪代码:
// 抽象咖啡制作类
abstract class CoffeeMaker {
public final void makeCoffee() {
boilWater();
grindBeans();
brewCoffee();
addOptional();
}
protected void boilWater() {
System.out.println("烧水");
}
protected void grindBeans() {
System.out.println("磨豆");
}
protected void brewCoffee() {
System.out.println("冲泡咖啡");
}
protected abstract void addOptional();
}
// 美式咖啡类
class Americano extends CoffeeMaker {
@Override
protected void addOptional() {
// 啥也不加
}
}
// 拿铁咖啡类
class Latte extends CoffeeMaker {
@Override
protected void addOptional() {
System.out.println("加奶加糖");
}
}
用这个模式,模板定好了大框架,子类按需填空白就行,代码复用率超高,还能满足不同的个性化需求,是不是很妙?
- 命令模式
举例:你去餐厅吃饭,点了几个菜,服务员把你点的菜记下来,当成一个个“命令”,交给厨房去执行。在代码里,比如有个图形绘制程序,有画圆、画矩形这些操作,每个操作封装成一个命令类,有个命令调用者负责触发执行,这样一来,如果要新增图形绘制功能,只需要新增对应的命令类,不影响其他部分。 伪代码:
// 抽象命令接口
interface Command {
void execute();
}
// 画圆命令类
class DrawCircleCommand implements Command {
@Override
public void execute() {
System.out.println("画一个圆");
}
}
// 画矩形命令类
class DrawRectangleCommand implements Command {
@Override
public void execute() {
System.out.println("画一个矩形");
}
}
// 命令调用者类
class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
使用的时候:
Invoker invoker = new Invoker();
invoker.setCommand(new DrawCircleCommand());
invoker.executeCommand();
- 状态模式
举例:咱就说那个交通信号灯哈,红灯、绿灯、黄灯轮流切换,不同灯亮的时候对应不同的通行规则,这就是状态变化。在代码里,比如电商订单有不同状态,待付款、已付款、已发货、已完成,每个状态下用户能做的操作不同,用状态模式把订单状态和对应的操作封装,订单状态切换时,行为跟着变,代码条理清晰得很。
伪代码:
// 抽象状态接口
interface OrderState {
void handle();
}
// 待付款状态类
class UnpaidState implements OrderState {
@Override
public void handle() {
System.out.println("请尽快付款");
}
}
// 已付款状态类
class PaidState implements OrderState {
@Override
public void handle() {
System.out.println("订单已付款,等待发货");
}
}
// 订单类,包含当前状态
class Order {
private OrderState state;
public Order(OrderState state) {
this.state = state;
}
public void setState(OrderState state) {
this.state = state;
}
public void handleOrder() {
state.handle();
}
}
切换状态示例:
Order order = new Order(new UnpaidState());
order.handleOrder();
order.setState(new PaidState());
order.handleOrder();
- 职责链模式
举例:公司请假流程晓得吧,你先跟组长请假,组长批了就完事,要是天数多,组长批不了,就往上找经理,经理再不行就找老板。这就是个职责链,一级一级传递审批请求。在代码里,比如处理网络请求,根据请求类型,先经过权限验证,再日志记录,最后业务处理,每个环节看成一个处理器,组成职责链,请求依次流过,符合条件就处理,不符合就传递给下一个。
伪代码:
// 抽象处理器接口
interface Handler {
void handleRequest(Request request);
void setNextHandler(Handler nextHandler);
}
// 权限验证处理器
class AuthHandler implements Handler {
private Handler nextHandler;
@Override
public void handleRequest(Request request) {
if (request.isValid()) {
System.out.println("权限验证通过");
if (nextHandler!= null) {
nextHandler.handleRequest(request);
}
} else {
System.out.println("权限验证失败");
}
}
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
}
// 日志记录处理器
class LogHandler implements Handler {
private Handler nextHandler;
@Override
public void handleRequest(Request request) {
System.out.println("记录日志");
if (nextHandler!= null) {
nextHandler.handleRequest(request);
}
}
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
}
// 业务处理器
class BusinessHandler implements Handler {
private Handler nextHandler;
@Override
public void handleRequest(Request request) {
System.out.println("执行业务逻辑");
if (nextHandler!= null) {
nextHandler.handleRequest(request);
}
}
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
}
组装并使用职责链:
AuthHandler authHandler = new AuthHandler();
LogHandler logHandler = new LogHandler();
BusinessHandler businessHandler = new BusinessHandler();
authHandler.setNextHandler(logHandler);
logHandler.setNextHandler(businessHandler);
Request request = new Request(true);
authHandler.handleRequest(request);
- 中介者模式
举例:像咱们办公室同事之间沟通哈,要是没有个协调人,A 找 B 谈事儿,B 又找 C 确认,乱得很。这时候有个项目经理(中介者),大家都跟他反馈,他再统筹安排,沟通就顺畅多了。在代码里,比如多个游戏角色交互,战士、法师、牧师,他们之间的技能配合、状态同步,如果都互相直接调用,代码耦合严重,引入中介者(游戏控制器),角色只和中介者交互,中介者协调角色间的行为。
伪代码:
// 抽象同事接口
interface Colleague {
void setMediator(Mediator mediator);
void sendMessage(String message);
void receiveMessage(String message);
}
// 战士角色类
class Warrior implements Colleague {
private Mediator mediator;
@Override
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
@Override
public void sendMessage(String message) {
mediator.sendMessage(message, this);
}
@Override
public void receiveMessage(String message) {
System.out.println("战士收到消息:" + message);
}
}
// 法师角色类
class Mage implements Colleague {
private Mediator mediator;
@Override
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
@Override
public void sendMessage(String message) {
mediator.sendMessage(message, this);
}
@Override
public void receiveMessage(String message) {
System.out.println("法师收到消息:" + message);
}
}
// 中介者接口
interface Mediator {
void sendMessage(String message, Colleague sender);
}
// 游戏控制器类,实现中介者接口
class GameController implements Mediator {
private Warrior warrior;
private Mage mage;
public void registerWarrior(Warrior warrior) {
this.warrior = warrior;
}
public void registerMage(Mage mage) {
this.mage = mage;
}
@Override
public void sendMessage(String message, Colleague sender) {
if (sender == warrior) {
mage.receiveMessage(message);
} else if (sender == mage) {
warrior.receiveMessage(message);
}
}
}
初始化并使用:
GameController gameController = new GameController();
Warrior warrior = new Warrior();
Mage mage = new Mage();
warrior.setMediator(gameController);
mage.setMediator(gameController);
gameController.registerWarrior(warrior);
gameController.registerMage(mage);
warrior.sendMessage("战士发起冲锋");
- 访问者模式
举例:你去逛博物馆哈,有不同的展品,每个展品有自己的介绍,游客(访问者)去参观的时候,展品就把自己的信息展示给游客。在代码里,比如有个电商系统的商品数据结构,有商品、订单、用户等不同类型的对象,要统计数据、生成报表,访问者模式就可以让统计报表类(访问者)去遍历这些对象,获取需要的数据,而不用在每个对象类里写复杂的统计逻辑,解耦效果明显。
伪代码:
// 抽象访问者接口
interface Visitor {
void visitProduct(Product product);
void visitOrder(Order order);
void visitUser(User user);
}
// 统计报表访问者类
class StatisticsVisitor implements Visitor {
private int productCount;
private int orderCount;
private int userCount;
@Override
public void visitProduct(Product product) {
productCount++;
}
@Override
public void visitOrder(Order order) {
orderCount++;
}
@Override
public void visitUser(User user) {
userCount++;
}
public void showStatistics() {
System.out.println("商品数量:" + productCount);
System.out.println("订单数量:" + orderCount);
System.out.println("用户数量:" + userCount);
}
}
// 抽象元素接口
interface Element {
void accept(Visitor visitor);
}
// 商品类,实现元素接口
class Product implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitProduct(this);
}
}
// 订单类,实现元素接口
class Order implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitOrder(this);
}
}
// 用户类,实现元素接口
class User implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitUser(this);
}
}
使用:
StatisticsVisitor visitor = new StatisticsVisitor();
Product product1 = new Product();
Product product2 = new Product();
Order order1 = new Order();
User user1 = new User();
product1.accept(visitor);
product2.accept(visitor);
order1.accept(visitor);
user1.accept(visitor);
visitor.showStatistics();
- 备忘录模式
定义:备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象到原先保存的状态。
详细描述: 它包含三个角色:原发器(Originator)负责创建备忘录并记录当前自身状态;备忘录(Memento)用于存储原发器的内部状态;负责人(Caretaker)负责保存备忘录,但不能对备忘录内容进行操作或访问。
举例说明:在文本编辑器软件中,当用户进行编辑操作时,编辑器可以随时保存当前文档的状态作为备忘录。如果用户误操作,如删除了大量重要内容,就可以从保存的备忘录中恢复之前的文档状态,让用户轻松回到某个历史版本,保证数据的安全性与可回溯性。
伪代码示例
// 备忘录类
class Memento {
private final String state;
Memento(String state) {
this.state = state;
}
String getState() {
return state;
}
}
// 原发器类
class Originator {
private String state;
void setState(String state) {
this.state = state;
}
String getState() {
return state;
}
Memento saveToMemento() {
return new Memento(state);
}
void restoreFromMemento(Memento memento) {
state = memento.getState();
}
}
// 负责人类
class Caretaker {
private final List<Memento> mementos = new ArrayList<>();
void addMemento(Memento memento) {
mementos.add(memento);
}
Memento getMemento(int index) {
return mementos.get(index);
}
}
- 解释器模式
定义:解释器模式(Interpreter Pattern)给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
详细描述:它将复杂的语言解析任务分解为一系列简单的解释操作,通过构建抽象语法树,让每个节点代表一个语法元素,由对应的解释器类来处理该节点的语义解释。
举例:在编译器开发中,对于源程序代码,解释器模式就大显身手了。例如,将高级编程语言编写的代码解析为机器能理解的指令。编译器会按照语法规则构建抽象语法树,不同的节点(如变量声明、函数调用、运算表达式等)由对应的解释器处理,最终将整个源程序转化为可执行的二进制代码。
伪代码示例 假设我们有一个简单的数学表达式解释器,支持加法和乘法运算。
// 抽象表达式
interface Expression {
int interpret();
}
// 终结符表达式 - 数字
class NumberExpression implements Expression {
private final int number;
NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
// 非终结符表达式 - 加法
class AddExpression implements Expression {
private final Expression left;
private final Expression right;
AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
// 非终结符表达式 - 乘法
class MultiplyExpression implements Expression {
private final Expression left;
private final Expression right;
MultiplyExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() * right.interpret();
}
}
- 迭代器模式
定义:迭代器模式(Iterator Pattern)提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
详细描述:它将遍历聚合对象的职责分离出来,通过迭代器对象来负责跟踪当前遍历位置、判断是否还有下一个元素等操作,让聚合对象专注于自身业务逻辑,同时为客户端提供统一的遍历接口。
举例说明:在 Java 的集合框架中,如 ArrayList、LinkedList 等都实现了迭代器模式。当我们需要遍历集合中的元素时,无需了解集合内部是如何存储数据的,只需获取对应的迭代器,通过迭代器的 hasNext 和 next 方法就能轻松遍历所有元素。例如,遍历一个存储学生成绩的 ArrayList,代码简洁清晰:
ArrayList<Integer> scores = new ArrayList<>();
scores.add(90);
scores.add(85);
scores.add(95);
Iterator<Integer> iterator = scores.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
伪代码示例
// 抽象迭代器
interface Iterator {
boolean hasNext();
Object next();
}
// 具体迭代器
class ConcreteIterator implements Iterator {
private final List<Object> list;
private int position = 0;
ConcreteIterator(List<Object> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return position < list.size();
}
@Override
public Object next() {
if (hasNext()) {
return list.get(position++);
}
return null;
}
}
// 抽象聚合类
interface Aggregate {
Iterator createIterator();
}
// 具体聚合类
class ConcreteAggregate implements Aggregate {
private final List<Object> list = new ArrayList<>();
void add(Object item) {
list.add(item);
}
@Override
public Iterator createIterator() {
return new ConcreteIterator(list);
}
}
掌握这些设计模式,能让我们在面对复杂的编程需求时,游刃有余地构建高质量的软件系统。它们不仅仅是代码技巧,更是编程思想的升华,助力每一位 Java 开发者迈向更高的编程境界。希望这篇文章能帮助大家加深对这些设计模式的理解,快去实践中运用起来吧!
三、Java 设计模式应用场景
Web 开发:在后端,像处理用户请求,路由分发可以用工厂模式创建不同请求处理器,根据 URL 精准匹配,高效处理;数据库连接管理,单例模式那是标配,保证资源利用最优,避免频繁创建销毁连接把数据库搞崩咯。前端页面构建,装饰器模式给组件加特效、样式,让页面颜值飙升,用户体验拉满。 游戏开发:角色系统,不同角色有不同技能、装备,工厂模式批量生成,快捷又方便;怪物 AI 行为,策略模式切换攻击、逃跑、巡逻套路,让怪物“聪明”起来;游戏关卡加载,模板方法模式定好通用流程,不同关卡个性化定制细节,开发效率蹭蹭涨。 企业级应用:权限管理,代理模式控制用户对敏感资源的访问,安全有保障;报表生成,按不同需求(日报、周报、年报)用策略模式选生成算法,数据精准呈现;系统模块间通信,观察者模式解耦,模块状态更新及时通知关联模块,协同作业不出错。
四、设计模式在不同框架中的应用
Spring 框架
Spring 里的 Bean 默认是单例模式,就像前面说的数据库连接池,整个应用上下文共享一个 Bean 实例,节省创建销毁开销,除非你特殊指定 @Scope("prototype") 改成原型模式,每次获取都新建。
Spring AOP(面向切面编程)底层用到代理模式,对目标对象生成代理,在方法执行前后切入自定义逻辑,比如事务管理,方法执行前开启事务,成功后提交,异常就回滚,代码无侵入,干净利落,业务代码不用操心事务细节,专注业务实现。
MyBatis 框架:在 SQL 语句执行映射这块,用到了建造者模式,把复杂的 SQL 构建过程封装,通过链式调用一步步组装查询条件、结果映射等,像 SelectBuilder.select("*").from("user").where("age > 18"),清晰又方便,比写一长串字符串 SQL 可读性强太多,维护起来也轻松。
JavaFX 框架:界面布局,布局管理器类似装饰器模式,给组件安排位置、大小,还能嵌套组合,像 BorderPane 给组件加边框布局,HBox、VBox 水平垂直排列组件,做出炫酷交互界面,用户操作手感一流。 各位码友,设计模式这玩意儿,学起来是要费点心思,但一旦掌握,代码质量那是质的飞跃,开发效率“爆棚”,以后面对复杂需求,都能淡定自若,轻松化解。赶紧动手把这些模式用到项目里试试,开启你的代码“开挂”之旅吧!要是还有啥不明白的,评论区见,咱一起探讨探讨。
后续我还会分享更多 Java 程序员相关的知识,记得关注怡格网,别错过精彩篇章哦!
最近一直在研究AI公众号爆文的运维逻辑,也在学习各种前沿的AI技术,加入了不会笑青年和纯洁的微笑两位大佬组织起来的知识星球,也开通了自己的星球:
怡格网友圈,地址是:https://wx.zsxq.com/group/51111855584224
这是一个付费的星球,暂时我还没想好里面放什么,现阶段不建议大家付费和进入我自己的星球,即使有不小心付费的,我也会直接退费,无功不受禄。如果你也对AI特别感兴趣,推荐你付费加入他们的星球:
AI俱乐部,地址是:https://t.zsxq.com/mRfPc 。
建议大家先加
微信号:yeegee2024
或者关注微信公众号:yeegeexb2014
咱们产品成型了之后,咱们再一起进入星球,一起探索更美好的未来!