【无标题】

写在前头

建议浏览我的blog网站来获得更佳观感
本文主要是个人初学Java理解设计模式和面向对象设计,对项目的一次总结,大佬请绕步,比较适合新手食用…

背景

源自于一次简单的程序实践课程,构建了一个基于控制台的轮渡管理系统(非常常规非常滴水…)。好像是大二上做的,对于大二的学生来讲再写这种控制台管理系统有些无聊了,毕竟之前就在大一上学期学完c就写了个链表的学生管理系统,被自己的屎山狠狠恶心(绝望)。所以在这一次的实践,心想能不能弄点好玩的打发时间,毕竟几乎要在机房里面坐牢好几天…

所以,我在快速写完了几个基本任务就开始在拓展点有趣的内容了。记得原本项目内容是要写一个管理一个船载几种车过船的,按照一种装载策略对应种类对应数量排好队上船开过去,然后记录信息。我就拓展了一下装载策略的部分。

想法

刚开始看到装载策略的时候,是想着改合理一点的,比如小车按位置,大车按吨位这样,但是于此同时我需要先实现原本的组合排队装载策略,保证能水过去这个实践,能不能我先实现组合排队,但是又能直接切换自己的策略又不影响之前的代码呢的方法呢🤔?

诶!我有个想法🤓☝,我们能不能先预设在装载时候的代码,对于装载逻辑预设一个槽位,然后编写一个符合这个槽位规格的方法放进去,只要(你是否在寻找:Spring)

于是乎我问了一下AI来给我来几个点子,现在的大模型AI也是一个某种意义上的baidu,帮忙找东西也挺方便的。最后,我就得到几种设计模式:

  • 核心模式:策略模式(动态切换算法)。

  • 增强模式:

    • 组合模式:实现策略的组合。

    • 工厂模式:简化策略实例的创建。

    • 装饰器模式:扩展策略的功能。

模板方法模式:统一管理通用逻辑。

思路
高拓展性——是我这个项目最想要实现的特性,所以基于这个目标我引入了这几种技术

控制反转 & 依赖注入,实现复杂的排队逻辑与执行类的解耦

策略模式,实现多种排队方法的切换,并且对方法与执行解耦,提高可维护性

实现&对比
对于这个简单的学习项目,我就不在这里过多讲述如何实现了,专注于文章的主题——设计模式的意义

策略模式
策略模式的核心思想是将算法封装成独立的类,并通过接口进行抽象。这样,客户端可以根据需要选择不同的算法实现,而无需修改客户端代码。

在这个项目中,对于多个方法来来说,他们都是一种排队方法,因此是可以实现一个抽象类的。但是对于排队方法来说,这个类更注重于执行方法中,因此应该是使用一个接口来实现这些排队方法的抽象。

接口LoadingRule代码

package rule;

import entity.vehicle.Vehicle;
import java.util.List;

public interface LoadingRule {
Vehicle selectNextVehicleToLoad(List selectionPool);
}
那么,如果一个方法想要被作为一种排队策略,那么这个方法类就需要实现接口LoadingRule中的接口方法selectNextVehicleToLoad 。通过这个接口,我们就实现了各个排队方法调用方式的统一,但是实现逻辑却是不一样的。

对于接口使用的碎碎念

举个栗子🌰,现在奶茶种类众多且名称复杂,你问店员有没有珍珠奶茶,他说“对不起先生,我们店内没有珍珠奶茶,只有QQㄋㄟㄋㄟ好喝到咩噗茶”,但是在如果你设置了一个珍珠奶茶的接口,规定把珍珠放进奶茶里面的就叫做珍珠奶茶,那么以后你去买珍珠奶茶就不用念千奇百怪的名字了(虽然视频店员回头下一秒就说了要一杯珍珠奶茶…)

控制反转&依赖注入
在通过LoadingRule接口解耦多个排队策略选择后,我们可以大概实现以下代码

private void loadVehicles() {
Ferry ferry = new Ferry(ferryList.size() + 1);

    whpackage entity;

import entity.vehicle.Vehicle;
import log.Log;
import rule.LoadingRule;
import rule.SimpleLoadingRule; // 或者 AdvancedLoadingRule

import java.util.*;

public class FerryTerminal {
private PriorityQueue waitingQueue = new PriorityQueue<>(Comparator.comparingLong(Vehicle::getArrivalTime));
private List ferryList = new ArrayList<>();
public Log log = new Log();
private LoadingRule loadingRule;

// 构造函数,内部创建 LoadingRule 实例
public FerryTerminal() {
    this.loadingRule = new SimpleLoadingRule(); // 或者 new AdvancedLoadingRule();
}

// 加入新车辆到等待队列
public void enqueueVehicle(Vehicle vehicle) {
    waitingQueue.offer(vehicle);
}

/**
 * 持续装载车辆到轮渡,直到所有车辆都被处理。
 */
public void startLoadingProcess() {
    while (!waitingQueue.isEmpty()) {
        loadVehicles();
    }
}

/**
 * 主要业务逻辑
 * 装载车辆到轮渡,并将装载完毕的轮渡加入到轮渡列表中。
 */
private void loadVehicles() {
    Ferry ferry = new Ferry(ferryList.size() + 1);

    while (ferry.getCurrentSize() < Ferry.MAX_SIZE && !waitingQueue.isEmpty()) {
        List<Vehicle> selectionPool = extractSelectionPool();
        Vehicle selectedVehicle = loadingRule.selectNextVehicleToLoad(selectionPool);

        if (selectedVehicle != null) {
            ferry.loadVehicle(selectedVehicle);
            log.recordVehicle(selectedVehicle, ferry.getId());
            selectionPool.remove(selectedVehicle);
        } else {
            break;
        }

        for (Vehicle v : selectionPool) {
            waitingQueue.offer(v);
        }
    }

    ferry.depart();
    ferryList.add(ferry);
}

private List<Vehicle> extractSelectionPool() {
    List<Vehicle> selectionPool = new ArrayList<>();
    int maxPoolSize = 6;
    for (int i = 0; i < maxPoolSize && !waitingQueue.isEmpty(); i++) {
        selectionPool.add(waitingQueue.poll());
    }
    return selectionPool;
}

}
对于上面使用LoadingRule接口实现策略模式,我们目前只解决了排队方法的切换和封装,但是还没有完全把方法实现内部解耦——换句话说,当我们需要选择不同策略时,我们需在执行类中编写对应的实现方法代码。

也就是说,目前我们通过策略模式,实现了方法代码与方法代码之间的解耦。

但是这里的执行者仍与策略实现代码有耦合,在设置具体实现方法中,我们是在执行者中通过new来添加的。如果我们要切换不同的策略,就需要重新打开这里的代码,改写new的类实例,也就是硬编码问题。

那博主博主,执行者中存在硬编码问题还是不够解耦,有没有更解耦一点的方式呢?有的兄弟有的(

为了让排队方法的创建硬编码解耦,我们可以把创建这件事情抛出到外面。即我们只管LoadingRule的使用,就像平常我们买一个肥皂,我们只负责使用肥皂,而肥皂怎么生产的我们却不需要管。根据项目需求设计,我们一次只用一个方法,因此可以在执行类的构造函数中,在new执行类时把实现LoadingRule接口的方法放进来。

于是乎,我们通过DI(依赖注入)的方式,实现了设计原则——IOC(控制反转)。把对象的创建和管理,从类内部转移到外部。

控制反转IOC与依赖注入DI的关系

IOC 是一种设计原则,强调将控制权从类内部转移到外部。

DI 是 IOC 的一种实现方式,通过构造函数、Setter 方法或接口等方式传递依赖项。

IOC 不一定需要 DI,还可以通过其他方式(如服务定位器模式)实现。

控制反转&依赖注入与策略模式

在我写这篇文章的时候,我也有一些对这两种方式的关系有点放分不开,因此在这里作为文章的重点也记录一下

(1) 策略模式与 IoC 的关系

策略模式关注的是算法的封装和互换,将不同的算法封装成独立的类。

IoC 关注的是对象的创建和管理,将对象的控制权反转给外部容器或框架。

虽然策略模式可以与 IoC 结合使用,但它们解决的问题不同:

策略模式 解决的是算法的封装和互换。

IoC 解决的是对象的创建和管理。

(2) 策略模式与 DI 的关系

策略模式 通过接口定义算法,具体算法由不同的实现类提供。

DI 通过外部注入依赖对象,使得依赖关系更加灵活。

在项目中,策略模式和 DI 可以结合使用,以实现更灵活的系统设计:

策略模式 定义了不同的装载规则。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值