黑马程序员Java设计模式详解, 23种Java设计模式(图解+框架源码分析+实
想学魔法的炜翼麻瓜
编辑于 2024年01月28日 16:56

⭐以下笔记包含对该课程所涉及细节问题的补充和弹幕里引发思考的讨论⭐

一、设计模式-创建者模式-模式拓展(简单工厂模式+配置文件)

11.设计模式-创建者模式-模式扩展(简单工厂模式+配置文件) P44 - 05:44

我认为读取配置文件和创建具体产品对象可以在具体工厂类的 createCoffee 静态方法里进行,而不是在类静态里提前创建好所有对象还存储在 map 里浪费内存

以下是我实现的代码,属于是随用随取、要用才生产:

public class CoffeeFactory {

public static Coffee createCoffee(String wantedCoffeeName) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

boolean isWantedCoffeeExist = false; //配置文件中是否有需求的产品

String coffeeClassName = ""; //具体产品的全类名

Properties coffeeProperties = new Properties();

coffeeProperties.load(CoffeeFactory.class.getClassLoader().getResourceAsStream("coffee.properties"));

Set<Object> coffeeNames = coffeeProperties.keySet();

for(Object coffeeName: coffeeNames){

//遍历配置文件检查是否有需求的产品

if (coffeeName.equals(wantedCoffeeName)){

isWantedCoffeeExist = true;

coffeeClassName = coffeeProperties.getProperty((String) coffeeName);

}

}

if (isWantedCoffeeExist == false){

throw new RuntimeException("所需求的咖啡产品不存在");

}else{

Class coffeeClass = Class.forName(coffeeClassName);

return (Coffee) coffeeClass.getConstructor().newInstance();

}

}

}

二、设计模式-创建者模式-建造者模式案例(生产自行车)

针对弹幕“如果我想要摩拜的车架加ofo的车座呢?”18.设计模式-创建者模式-建造者模式案例(生产自行车) P51 - 09:56 弹幕坐标

我修改了建造者设计模式,由指挥者创建初始对象,而建造者则通过引用对象设置产品的样貌与特征,使得可以搭配“摩拜的车架”和“ofo的车座”

代码实现:

① 产品类

public class Computer {

private String cpu;

private String gpu;

public Computer() {

}

public String getCpu() {

return cpu;

}

public void setCpu(String cpu) {

this.cpu = cpu;

}

public String getGpu() {

return gpu;

}

public void setGpu(String gpu) {

this.gpu = gpu;

}

public String toString() {

return "Computer{cpu = " + cpu + ", gpu = " + gpu + "}";

}

}er

② 抽象建造者

public abstract class Manufacturer {

protected Computer computer;

public void deliverComputer(Computer computer){

this.computer = computer;

}

public abstract void buildCpu();

public abstract void buildGpu();

}

③ 具体建造者

public class Intel extends Manufacturer {

@Override

public void buildCpu() {

computer.setCpu("酷睿处理器");

}

@Override

public void buildGpu() {

computer.setGpu("锐炬显卡");

}

}

public class Amd extends Manufacturer{

@Override

public void buildCpu() {

computer.setCpu("锐龙处理器");

}

public void buildGpu() {

computer.setGpu("ATI显卡");

}

}

public class Nvidia extends Manufacturer{

@Override

public void buildCpu() {

computer.setCpu("null");

}

@Override

public void buildGpu() {

computer.setGpu("RTX显卡");

}

}

④ 指挥者

public class Designer {

private Computer computer = new Computer();

private HashMap<String, Manufacturer> hardwareDesignList = new HashMap<>();

public void addDesign(String hardwareName, Manufacturer hardwareBrand){

hardwareDesignList.put(hardwareName, hardwareBrand);

}

public void removeDesign(String hardwareName){

hardwareDesignList.remove(hardwareName);

}

public Computer constuct(){

Set<String> hardwareNames = hardwareDesignList.keySet();

for(String hardwareName: hardwareNames){

Manufacturer hardwareBrand = hardwareDesignList.get(hardwareName);

hardwareBrand.deliverComputer(computer);

if(hardwareName.equals("CPU")){

hardwareBrand.buildCpu();

}else if(hardwareName.equals("GPU")){

hardwareBrand.buildGpu();

}

}

return computer;

}

}

三、设计模式-结构型模式-CGLIB代理实现案例(火车站卖票)

6.设计模式-结构型模式-CGLIB代理实现案例(火车站卖票) P60 - 09:56 运行 CGLIB 动态代理

幕反映 CGLIB 动态代理运行报错:

Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module

是因为 Java 9 及更高版本模块化系统的引入导致了对某些反射操作的限制,而 CGLIB 就是调用了一些受保护的 API

解决方法是添加 JVM 启动参数:

--add-opens=java.base/java.lang.reflect=ALL-UNNAMED

四、设计模式-结构型模式-桥接模式概述

根据后面的22.设计模式-结构型模式-桥接模式案例实现 P76 - 07:08 聚合实现化角色案例,21.设计模式-结构型模式-桥接模式概述 P75 - 03:04 组合关系?处应该准确表述为“聚合关系”,区别就在于聚合是从外部引用所关联的对象,而组合则是由内部创建所关联的对象

五、设计模式-行为型模式-命令模式案例实现

针对弹幕“客户做的太多了吧”21.设计模式-行为型模式-命令模式案例实现 P102 - 17:12 弹幕坐标

可以把生成请求也集成进发出者里,将 Waitor 类的 SetCommand 方法改成 addOrder 方法,代码实现修改为:

public void addOrder(SeniorChef receivor, Order order){

commands.add(new OrderCommand(receivor, order));

}

但这会使得具体命令与发出者耦合,所以代码不能这么改,毕竟请求是来源于客户而不是服务员

可以选择将 Order 类的 setDiningTable 方法和 setFoodDir 方法改成链式调用精简 Order 对象的使用,代码实现修改为:

public Order setDiningTable(int diningTable) {

this.diningTable = diningTable;

return this;

}

public Order setFoodDir(String name, Integer num) {

foodDir.put(name, num);

return this;

}

最终 Client 的代码会精简不少

waitor.setCommand(

new OrderCommand(

new SeniorChef(),

new Order()

.setDiningTable(1)

.setFoodDir("西红柿鸡蛋面", 1)

)

);