首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,082 阅读
2
类的加载
741 阅读
3
Spring Cloud OAuth2.0
726 阅读
4
SpringBoot自动装配原理
691 阅读
5
集合不安全问题
584 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
388
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
页面
统计
关于
搜索到
29
篇与
的结果
2022-09-05
结构型模式-装饰者模式
(1)概述在不改变现有对象结构的情况下,动态的给该对象增加额外的职责或功能(2)结构抽象构建角色:定义一个抽象接口以规范准备接收附加责任的对象具体构建角色:实现抽象构建,通过装饰角色为其添加一些职责抽象装饰角色:继承或实现抽象构建,并包含具体构建的实例,可以通过其子类扩展具体构建的功能具体装饰角色:实现抽象装饰的相关方法,并给具体构建对象添加附加的职责或功能(3)案例以快餐店为例:抽象构建角色public abstract class FastFood { private float price; private String desc; public FastFood() { } public FastFood(float price, String desc) { this.price = price; this.desc = desc; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } /** * 计算价格 * * @return */ public abstract float cost(); }具体构建角色public class FriedNoodles extends FastFood { public FriedNoodles() { super(8, "炒面"); } @Override public float cost() { return super.getPrice(); } } public class FriedRice extends FastFood { public FriedRice() { super(10, "炒饭"); } @Override public float cost() { return super.getPrice(); } }抽象装饰角色public abstract class Garnish extends FastFood { private FastFood fastFood; public Garnish(FastFood fastFood, float price, String desc) { super(price, desc); this.fastFood = fastFood; } public FastFood getFastFood() { return fastFood; } public void setFastFood(FastFood fastFood) { this.fastFood = fastFood; } }具体装饰角色public class Egg extends Garnish { public Egg(FastFood fastFood) { super(fastFood, 1, "鸡蛋"); } @Override public float cost() { //价格:鸡蛋 + 快餐的价格 return super.getPrice() + super.getFastFood().cost(); } @Override public String getDesc() { //描述:鸡蛋 + 具体的快餐 return super.getDesc() + super.getFastFood().getDesc(); } } public class Bacon extends Garnish { public Bacon(FastFood fastFood) { super(fastFood, 2, "培根"); } @Override public float cost() { //价格:培根 + 快餐的价格 return super.getPrice() + super.getFastFood().cost(); } @Override public String getDesc() { //描述:培根 + 具体的快餐 return super.getDesc() + super.getFastFood().getDesc(); } }测试public class Client { public static void main(String[] args) { //炒饭 FastFood food = new FriedRice(); System.out.println(food.getDesc() + " " + food.cost() + "元"); //再加一个鸡蛋 food = new Egg(food); //System.out.println(food.getDesc() + " " + food.cost() + "元"); //加培根 food = new Bacon(food); System.out.println(food.getDesc() + " " + food.cost() + "元"); } }(4)优缺点装饰者模式可以带来比继承更加灵活的扩展功能,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任装饰类和被装饰类可以各自独立发展,不会产生耦合,装饰者模式是继承的一个替代模式,可以动态扩展一个实现类的功能(5)使用场景当不能采用继承的方式对系统进行扩充或采用继承不利于系统扩展和维护时类中存在大量独立的扩展,使用继承可能会造成类爆炸时被 final 修饰的类在不影响其他对象的情况下,以动态、透明的方式给单个对象添加功能或职责当对象的功能要求动态添加,动态移除时(6)静态代理与装饰者模式的区别相同点:都要实现与目标类相同的业务接口在两个类中都要声明目标对象都可以在不修改目标对象的前提下进行功能增强不同点:目的不同:装饰者增强目标对象静态代理保护和隐藏目标对象获取目标对象构建的地方不同装饰者中的目标对象由外界传递(通过构造方法或set赋值)静态代理的目标对象在代理类内部创建,以此来完成隐藏和保护
2022年09月05日
27 阅读
0 评论
0 点赞
2022-09-04
结构型模式-适配器模式
(1)概述将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类能一起工作,分为类适配器模式(耦合度高)和对象适配器模式(2)结构目标接口:当前系统业务所期待的接口(抽象类或接口)适配者类:它是被访问和适配的现存组件库中的组件接口适配器类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者(3)类适配器模式实现方式:定义一个适配器类来实现当前系统的业务接口(即目标接口),同时又继承现有组件库中已经存在的组件(即适配者类)以读卡器为例:目标接口public interface SDCard { /** * 读数据 * * @return */ String readSD(); /** * 写数据 * * @param msg */ void writeSD(String msg); }具体的SD卡类public class SDCardImpl implements SDCard { @Override public String readSD() { return "Read data from SDCard: Hello World"; } @Override public void writeSD(String msg) { System.out.println("Write data to SDCard:" + msg); } }public class Computer { public String readSD(SDCard sdCard) { if (sdCard == null) { throw new NullPointerException("SDCard can not be null"); } return sdCard.readSD(); } }适配者类接口public interface TFCard { /** * 读数据 * * @return */ String readTF(); /** * 写数据 * * @param msg */ void writeTF(String msg); }适配者类public class TFCardImpl implements TFCard { @Override public String readTF() { return "Read data from TFCard: Hello World"; } @Override public void writeTF(String msg) { System.out.println("Write data to TFCard:" + msg); } }适配器类public class SDAdapterTF extends TFCardImpl implements SDCard { @Override public String readSD() { System.out.println("Adapter read from TFCard"); return super.readTF(); } @Override public void writeSD(String msg) { System.out.println("Adapter write to TFCard"); super.writeTF(msg); } }测试public class Client { public static void main(String[] args) { //计算机 Computer computer = new Computer(); //读取SDCard中的数据 String msg = computer.readSD(new SDCardImpl()); System.out.println(msg); System.out.println("===================================="); //使用该电脑读取TFCard中的数据 //定义适配器类 String msg1 = computer.readSD(new SDAdapterTF()); System.out.println(msg1); } }类适配器模式违背了合成复用原则,在客户类有一个明确的接口规范的情况下可用,反之不可用(4)对象适配器模式实现方式:采用将现有组件库中已实现的组件引入适配器类中,该类同时实现当前系统的业务接口读卡器案例改进:目标接口public interface SDCard { /** * 读数据 * * @return */ String readSD(); /** * 写数据 * * @param msg */ void writeSD(String msg); }具体的SD卡类public class SDCardImpl implements SDCard { @Override public String readSD() { return "Read data from SDCard: Hello World"; } @Override public void writeSD(String msg) { System.out.println("Write data to SDCard:" + msg); } }public class Computer { public String readSD(SDCard sdCard) { if (sdCard == null) { throw new NullPointerException("SDCard can not be null"); } return sdCard.readSD(); } }适配者类接口public interface TFCard { /** * 读数据 * * @return */ String readTF(); /** * 写数据 * * @param msg */ void writeTF(String msg); }适配者类public class TFCardImpl implements TFCard { @Override public String readTF() { return "Read data from TFCard: Hello World"; } @Override public void writeTF(String msg) { System.out.println("Write data to TFCard:" + msg); } }适配器类public class SDAdapterTF implements SDCard { //适配者类 private TFCard tfCard; public SDAdapterTF(TFCard tfCard) { this.tfCard = tfCard; } @Override public String readSD() { System.out.println("Adapter read from TFCard"); return tfCard.readTF(); } @Override public void writeSD(String msg) { System.out.println("Adapter write to TFCard"); tfCard.writeTF(msg); } }测试public class Client { public static void main(String[] args) { //计算机 Computer computer = new Computer(); //读取SDCard中的数据 String msg = computer.readSD(new SDCardImpl()); System.out.println(msg); System.out.println("===================================="); //使用该电脑读取TFCard中的数据 String msg1 = computer.readSD(new SDAdapterTF(new TFCardImpl())); System.out.println(msg1); } }对象适配器模式解决了类适配器模式中存在的问题;同时还有接口适配器模式,当不希望实现一个接口中的所有方法时,可以定义一个 Adapter 抽象类,实现目标接口中的所有方法,适配器类再继承该抽象类,根据需要选择所需的方法(5)应用场景原系统存在满足新系统功能需求的类,但存在接口不一致的问题时使用第三方提供的组件,但所需组件接口与自己接口定义不同的时候
2022年09月04日
47 阅读
0 评论
0 点赞
2022-09-04
结构型模式-代理模式
结构型模式描述如何将类或对象按某种布局组合成更大的结构,分为类结构型模式和对象结构型模式,前者采用继承来组织接口和类,后者采用组合或聚合来组合对象分为:代理模式、适配器模式、装饰者模式、桥接模式、外观模式、组合模式、享元模式1. 代理模式(1)概述由于某些原因需要给某对象提供一个代理以控制对该对象的访问,这时,访问对象不适合或不能直接引用目标对象,代理对象作为访问对象与目标对象之间的中介Java中的代理按照类生成时机的不同分为静态代理和动态代理,静态代理 代理类在编译时生成,动态代理 代理类在运行时动态生成(JDK动态代理、CGLib动态代理)(2)结构抽象主题类:通过接口或抽象类声明真实主题和代理对象实现的业务方法真实主题类:实现抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象代理类:提供与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制以及扩展真实主题的功能(3)静态代理以火车站卖票为例抽象主题类public interface SellTickets { /** * 卖票 */ void sell(); }真实主题类public class TrainStation implements SellTickets { @Override public void sell() { System.out.println("火车站卖票"); } }代理类public class ProxyPoint implements SellTickets { /** * 聚合火车站对象 */ private TrainStation trainStation = new TrainStation(); @Override public void sell() { System.out.println("代售点收取5元手续费"); trainStation.sell(); } }测试public class Client { public static void main(String[] args) { //创建代售点 ProxyPoint proxyPoint = new ProxyPoint(); //顾客从代售点买票 proxyPoint.sell(); } }(4)JDk动态代理抽象主题类public interface SellTickets { /** * 卖票 */ void sell(); }真实主题类public class TrainStation implements SellTickets { @Override public void sell() { System.out.println("火车站卖票"); } }获取代理对象的工厂类public class ProxyFactory { /** * 声明目标对象 */ private final TrainStation trainStation = new TrainStation(); /** * 获取代理对象 * * @return */ public SellTickets getProxyInstance() { //返回代理对象 /** * ClassLoader loader:类加载器(可以通过目标对象获取类加载器) * Class<?>[] interfaces:代理类实现的接口的字节码对象 * InvocationHandler h:代理对象的调用处理程序 */ return (SellTickets) Proxy.newProxyInstance( trainStation.getClass().getClassLoader(), trainStation.getClass().getInterfaces(), new InvocationHandler() { /** * Object proxy:代理对象,和proxyObject是同一个对象,在invoke方法中基本不用 * Method method:对接口中的方法进行封装的method对象 * Object[] args:调用方法的实际参数 * 返回值:方法的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代售点收取10元手续费(jdk动态代理)"); //执行目标对象的方法 return method.invoke(trainStation, args); } }); } }测试public class Client { public static void main(String[] args) { //获取代理对象 //1.创建代理工厂对象 ProxyFactory proxyFactory = new ProxyFactory(); //2.使用proxyFactory对象的方法获取代理对象 SellTickets proxyObject = proxyFactory.getProxyInstance(); //3.调用卖票的方法 proxyObject.sell(); } }Java中提供了一个动态代理类 Proxy ,即提供了一个创建代理对象的静态方法 newProxyInstance 来获取代理对象使用Arthas (阿尔萨斯)查看代理类的结构:package com.sun.proxy; import com.itheima.proxy.dynamic.jdk.SellTickets; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements SellTickets { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler invocationHandler) { super(invocationHandler); } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.itheima.proxy.dynamic.jdk.SellTickets").getMethod("sell", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException noSuchMethodException) { throw new NoSuchMethodError(noSuchMethodException.getMessage()); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError(classNotFoundException.getMessage()); } } public final boolean equals(Object object) { try { return (Boolean)this.h.invoke(this, m1, new Object[]{object}); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return (Integer)this.h.invoke(this, m0, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final void sell() { try { this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }从以上类结构可以看出:代理类 $Proxy0 实现了 SellTickets,即真实类和代理类都实现了同样的接口代理类 $Proxy0 将我们提供了的匿名内部类 invocationHandler 传递给了父类动态代理执行流程:在测试类(访问类)中通过代理对象调用 sell() 方法根据多态的特性,执行的代理类是 $Proxy0 中的 sell() 方法代理类 $Proxy0 中的 sell() 方法中又调用了 invocationHandler 接口的子实现类对象的 invoke() 方法invoke 方法通过反射执行了真实对象所属类 TrainStation 中的 sell() 方法(5)CGLib动态代理如果没有定义 SellTickets 接口,只定义了 TrainStation 火车站类,此时无法使用JDK动态代理,因为它要求必须定义接口真实主题类public class TrainStation { public void sell() { System.out.println("火车站卖票"); } }代理对象工厂public class ProxyFactory implements MethodInterceptor { /** * 声明火车站对象 */ private TrainStation trainStation = new TrainStation(); public TrainStation getProxyObject() { //创建Enhancer对象(类似于JDK代理中的Proxy) Enhancer enhancer = new Enhancer(); //设置父类的字节码对象 enhancer.setSuperclass(TrainStation.class); //设置回调函数 enhancer.setCallback(this); //创建代理对象 TrainStation proxyObject = (TrainStation) enhancer.create(); return proxyObject; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代售点收取15元手续费(CGLib代理)"); //要调用目标方法的对象 return method.invoke(trainStation, objects); } }测试public class Client { public static void main(String[] args) { //代理工厂 ProxyFactory proxyFactory = new ProxyFactory(); //获取代理对象 TrainStation proxyObject = proxyFactory.getProxyObject(); //调用sell proxyObject.sell(); } }(6)三种代理模式的对比静态代理与动态代理:动态代理将接口中声明的所有方法都转移到调用处理器一个集中的方法中处理(JDK:InvocationHandler.invoke()),在接口方法较多的情况下可以进行灵活的处理;反之静态代理每增加一个方法就需要新增对应的代理类JDK与CGLib动态代理:CGLib 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类,在 JDK1.6 之前比使用 Java反射效率要高,其中需注意:CGLib 不能对声明为 final 类型的类或方法进行代理,因为 CGLib 原理是动态生成被代理类的子类在JDK1.6、1.7、1.8逐步优化之后,在调用次数较少的情况下,其效率高于 CGLib 动态代理,在大量调用的情况下,CGLib 效率优于 JDK1.6、1.7,JDK1.8 时效率高于 CGLib有接口时使用JDK动态代理,没有接口时使用CGLib动态代理(7)优缺点代理模式在客户端与目标对象之间起到中介的作用和保护目标对象的作用可以扩展目标对象的功能将客户端与目标对象分离,降低了耦合度增加了系统的复杂度(8)使用场景远程代理(Remote)本地服务通过网络请求远程服务,将通信部份隐藏起来,只暴露给本地服务一个接口,通过该接口访问远程服务所提供的功能,而不必过多关心通信细节的部分,如:RPC 远程调用防火墙代理在浏览器配置代理功能时,防火墙将请求转发给互联网,收到响应之后再转发给浏览器保护代理控制一个对象的访问,可以给不同的用户提供不同的使用权限
2022年09月04日
96 阅读
0 评论
0 点赞
2022-08-31
创建者模式-建造者模式
(1)概述将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示(2)结构抽象建造者类(Builder):该接口规定要实现复杂对象的哪些部分的创建,并不涉及具体部件的创建具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂对象的各个部件的具体创建方法,在构造过程完成后,提供产品的实例产品类(Product):要创建的复杂对象指导者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建(3)实例以生产单车为例public class Bike { private String frame; private String seat; public String getFrame() { return frame; } public void setFrame(String frame) { this.frame = frame; } public String getSeat() { return seat; } public void setSeat(String seat) { this.seat = seat; } }public abstract class Builder { protected Bike bike = new Bike(); /** * 生产车架 */ public abstract void buildFrame(); /** * 生产车座 */ public abstract void buildSeat(); /** * 生产自行车 * * @return */ public abstract Bike createBike(); public Bike construct() { this.buildFrame(); this.buildSeat(); return this.createBike(); } }public class QingJuBuilder extends Builder{ @Override public void buildFrame() { bike.setFrame("青桔牌车架"); } @Override public void buildSeat() { bike.setSeat("青桔牌车座"); } @Override public Bike createBike() { return bike; } } public class MeiTuanBuilder extends Builder { @Override public void buildFrame() { bike.setFrame("美团牌车架"); } @Override public void buildSeat() { bike.setSeat("美团牌车座"); } @Override public Bike createBike() { return bike; } }public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } /** * 组装自行车 */ public Bike construct() { builder.buildFrame(); builder.buildSeat(); return builder.createBike(); } }public class Client { public static void main(String[] args) { //指导者 Director director = new Director(new QingJuBuilder()); //指导者指导生产自行车 Bike bike = director.construct(); System.out.println(bike.getFrame()); System.out.println(bike.getSeat()); } }以上实例可以将指导者和抽象建造者结合,这样做可以简化系统复杂度,但不符合单一职责原则public abstract class Builder { protected Bike bike = new Bike(); /** * 生产车架 */ public abstract void buildFrame(); /** * 生产车座 */ public abstract void buildSeat(); /** * 生产自行车 * * @return */ public abstract Bike createBike(); public Bike construct() { this.buildFrame(); this.buildSeat(); return this.createBike(); } }(5)优缺点封装性好,建造者模式可以有效的封装变化,在该过程中,产品类与建造者类相对稳定,将复杂的业务逻辑封装在指导者类中对整体而言有较好的稳定性在建造者模式中,客户端无需关心产品内部组成的细节,将产品本身与创建的过程解耦,使得相同的创建过程可以建造不同的产品可以更细粒度的控制产品的创建过程,即将复杂对象的创建步骤分解在不同的方法中,可以使创建过程更加清晰,也可以更好的控制创建过程易扩展,当有同类产品的新的需求时,新增一个建造者就可以完成,符合开闭原则建造者模式所创建的产品一般来说有较多的相同点,其组成部分相似,如果产品之间差异较大,则不适合使用建造者模式,使其适用范围受限(6)使用场景创建的对象较复杂,有多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的(7)扩展当一个类的构造器需要传入很多参数时,如果创建该类的实例,可能导致代码可读性差和引入新的错误,此时可以使用建造者模式进行重构public class Phone { private String cpu; private String screen; private String memory; private String mainBoard; //私有构造器 private Phone(Builder builder) { this.cpu = builder.cpu; this.screen = builder.screen; this.memory = builder.memory; this.mainBoard = builder.mainBoard; } public static final class Builder { private String cpu; private String screen; private String memory; private String mainBoard; public Builder cpu(String cpu) { this.cpu = cpu; return this; } public Builder screen(String screen) { this.screen = screen; return this; } public Builder memory(String memory) { this.memory = memory; return this; } public Builder mainBoard(String mainBoard) { this.mainBoard = mainBoard; return this; } //使用建造者创建Phone对象 public Phone build() { return new Phone(this); } } @Override public String toString() { return "Phone{" + "cpu='" + cpu + '\'' + ", screen='" + screen + '\'' + ", memory='" + memory + '\'' + ", mainBoard='" + mainBoard + '\'' + '}'; } }
2022年08月31日
57 阅读
0 评论
0 点赞
2022-08-30
创建者模式-原型模式
(1)概述用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象(2)结构抽象原型类:规定了具体原型对象必须实现的 clone() 方法具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象访问类:使用具体原型类中的 clone() 方法来复制新的对象接口类图:(3)实现原型模式的克隆分为浅克隆和深克隆:浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型,仍指向原有属性所指向的对象的内存地址深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,且不再指向原有对象地址Java中 Object 类提供了 clone() 方法来实现浅克隆,Cloneable 接口是上面类图中的抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类。原型类public class Realizetype implements Cloneable { public Realizetype() { System.out.println("具体原型对象创建完成"); } @Override public Realizetype clone() throws CloneNotSupportedException { System.out.println("具体原型复制成功"); return (Realizetype) super.clone(); } }测试public class Client { public static void main(String[] args) throws CloneNotSupportedException { //创建原型对象 Realizetype realizetype = new Realizetype(); //调用clone方法进行对象的克隆 Realizetype realizetype1 = realizetype.clone(); //具体原型对象创建完成 //具体原型复制成功 //false System.out.println(realizetype == realizetype1); } }(4)案例以学校发放“三好学生”奖状为例public class Citation implements Cloneable { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void show() { System.out.println(name + "同学,在本学年表现优秀,被评为“三好学生”,特发此状,以资鼓励!"); } @Override public Citation clone() throws CloneNotSupportedException { return (Citation) super.clone(); } }public class CitationTest { public static void main(String[] args) throws CloneNotSupportedException { //创建原型对象 Citation citation = new Citation(); //复制奖状 Citation citation1 = citation.clone(); citation.setName("孙笑川"); citation1.setName("药水哥"); //展示奖状 citation.show(); citation1.show(); } }(5)使用场景对象的创建非常复杂性能和安全要求较高(6)深克隆将奖状案例中的 name 属性修改为 Student 复杂对象属性public class CitationTest { public static void main(String[] args) throws CloneNotSupportedException { //创建原型对象 Citation citation = new Citation(); //创建学生 Student student = new Student(); student.setName("孙笑川"); citation.setStudent(student); //复制奖状 Citation citation1 = citation.clone(); citation1.getStudent().setName("药水哥"); //展示奖状 citation.show(); citation1.show(); //药水哥同学,在本学年表现优秀,被评为“三好学生”,特发此状,以资鼓励! //药水哥同学,在本学年表现优秀,被评为“三好学生”,特发此状,以资鼓励! } }存在的问题:使用浅克隆时,克隆出来的对象属性中的 student1 和第一次创建的 student 是同一个对象,此时 setName 方法设置的值是同一个改进:(使用对象流)public class CitationTest { public static void main(String[] args) throws Exception { //创建原型对象 Citation citation = new Citation(); //创建学生 Student student = new Student(); student.setName("孙笑川"); citation.setStudent(student); //创建对象输出流 ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("D:/citation.txt"))); //写对象 oos.writeObject(citation); //释放资源 oos.close(); //创建对象 ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get("D:/citation.txt"))); Citation citation1 = (Citation) ois.readObject(); ois.close(); citation1.getStudent().setName("药水哥"); citation.show(); citation1.show(); //孙笑川同学,在本学年表现优秀,被评为“三好学生”,特发此状,以资鼓励! //药水哥同学,在本学年表现优秀,被评为“三好学生”,特发此状,以资鼓励! } }
2022年08月30日
36 阅读
0 评论
0 点赞
2022-08-27
创建者模式-工厂模式
(1)概述以咖啡店点餐系统为例:当需要添加不同类型的咖啡的时候,需要修改原有的代码,违背了开闭原则,此时如果使用工厂来生产不同类型的咖啡,则只需要与工厂产生对接,工厂模式的最大优点即解耦(2)简单工厂模式简单工厂模式不属于GOF的23种经典设计模式,其更像是一种编程习惯结构抽象产品:定义产品的规范,描述产品的主要特性和功能具体产品:实现或继承抽象产品的子类具体工厂:提供创建产品的方法,调用者通过该方法来获取产品实现工厂处理创建对象的细节,一旦有了 SimpleCoffeeFactory 工厂类,CoffeeStore 类中的 orderCoffee() 就变成此对象的客户,后期如果需要 Coffee 对象直接从工厂获取即可,解除了和 Cooffee 实现类的耦合,但同时又产生了新的耦合:CoffeeStore 对象与 SimpleCoffeeFactory 工厂对象,SimpleCoffeeFactory 工厂对象 与 生产的商品对象CoffeeStorepublic class CoffeeStore { public Coffee orderCoffee(String type) { //通过简单工厂生产咖啡 SimpleCoffeeFactory factory = new SimpleCoffeeFactory(); Coffee coffee = factory.createCoffee(type); //加配料 coffee.addSugar(); coffee.addMilk(); return coffee; } }SimpleCoffeeFactorypublic class SimpleCoffeeFactory { public Coffee createCoffee(String type) { //声明coffee类型的变量,根据不同类型创建不同的coffee子类 Coffee coffee = null; if ("american".equals(type)) { coffee = new AmericanCoffee(); } else if ("latte".equals(type)) { coffee = new LatteCoffee(); } else { throw new RuntimeException("该类型的咖啡暂未上架"); } return coffee; } }Coffeepublic abstract class Coffee { /** * 获取咖啡名字 * * @return */ public abstract String getName(); public void addSugar() { System.out.println("加糖"); } public void addMilk() { System.out.println("加奶"); } }AmericanCoffeepublic class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }LatteCoffeepublic class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }Clientpublic class Client { public static void main(String[] args) { CoffeeStore coffeeStore = new CoffeeStore(); Coffee coffee = coffeeStore.orderCoffee("american"); System.out.println(coffee.getName()); } }优缺点封装了创建对象的过程,可以通过参数直接获取对象,把对象的创建与业务逻辑分开,避免了修改客户端代码,如果要添加新的产品则直接修改工厂类增加新产品时需要修改原有的工厂类,违背了开闭原则扩展(静态工厂)public class SimpleCoffeeFactory { public static Coffee createCoffee(String type) { //声明coffee类型的变量,根据不同类型创建不同的coffee子类 Coffee coffee = null; if ("american".equals(type)) { coffee = new AmericanCoffee(); } else if ("latte".equals(type)) { coffee = new LatteCoffee(); } else { throw new RuntimeException("该类型的咖啡暂未上架"); } return coffee; } }(2)工厂方法模式概念定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象,工厂方法使一个产品类的实例化延迟到其工厂的子类结构抽象工厂:提供创建产品的接口,调用者通过它访问具体工厂的方法来创建产品具体工厂:实现抽象工厂中的抽象方法,完成具体产品的创建抽象产品:定义产品的规范,描述产品的主要功能和特性具体产品:实现抽象产品定义的接口,由具体工厂来创建(与具体工厂一一对应)实现工厂方法模式是简单工厂模式的进一步抽象,由于使用了多态,既保持了简单工厂模式的优点,同时也解决了它的缺点抽象工厂CoffeeFactorypublic interface CoffeeFactory { /** * 创建咖啡对象 * * @return */ Coffee createCoffee(); }具体工厂AmericanCoffeeFactorypublic class AmericanCoffeeFactory implements CoffeeFactory { @Override public Coffee createCoffee() { return new AmericanCoffee(); } }LatteCoffeeFactorypublic class LatteCoffeeFactory implements CoffeeFactory { @Override public Coffee createCoffee() { return new LatteCoffee(); } }咖啡店类CoffeeStorepublic class CoffeeStore { private CoffeeFactory factory; public void setFactory(CoffeeFactory factory) { this.factory = factory; } public Coffee orderCoffee() { Coffee coffee = factory.createCoffee(); coffee.addMilk(); coffee.addSugar(); return coffee; } }Coffeepublic abstract class Coffee { /** * 获取咖啡名字 * * @return */ public abstract String getName(); public void addSugar() { System.out.println("加糖"); } public void addMilk() { System.out.println("加奶"); } }AmericanCoffeepublic class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }LatteCoffeepublic class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }Clientpublic class Client { public static void main(String[] args) { //咖啡店 CoffeeStore store = new CoffeeStore(); //咖啡工厂 //AmericanCoffeeFactory factory = new AmericanCoffeeFactory(); LatteCoffeeFactory factory = new LatteCoffeeFactory(); store.setFactory(factory); //点咖啡 Coffee coffee = store.orderCoffee(); System.out.println(coffee.getName()); } }优缺点用户只需要知道具体工厂的名称就能得到需要的产品,无需关心产品的具体创建过程增加新的产品时只需添加具体产品类和对应的工厂类,无须对原工厂进行修改,满足开闭原则每增加一个产品就要增加一个具体产品类和对应的工厂类,增加了系统的复杂度(3)抽象工厂模式概念为访问类提供一个创建一组或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构结构抽象工厂:提供创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建抽象产品:定义产品的规范,描述产品的主要功能和特性(抽象工厂模式具有多个抽象产品)具体产品:实现抽象产品角色所定义的接口,由具体工厂来创建,它与具体工厂之间是多对一的关系实现当咖啡店业务发生变化时,不仅要上架咖啡,还需要上架甜点(提拉米苏、抹茶慕斯),按照工厂方法模式,很容易发生类爆炸的问题;其中:拿铁、美式属于一个产品等级,都是咖啡;提拉米苏、抹茶慕斯属于一个产品等级,都是甜点;拿铁、提拉米苏属于一个产品类别,都是意大利风味;美式、抹茶慕斯属于一个产品类别,都是美式风味可以使用抽象工厂模式来实现:抽象工厂public interface DessertFactory { /** * 生产咖啡 * * @return */ Coffee createCoffee(); /** * 生产甜品 * * @return */ Dessert createDessert(); }具体工厂public class AmericanDessertFactory implements DessertFactory { @Override public Coffee createCoffee() { return new AmericanCoffee(); } @Override public Dessert createDessert() { return new MatchaMousse(); } } public class ItalyDessertFactory implements DessertFactory { @Override public Coffee createCoffee() { return new LatteCoffee(); } @Override public Dessert createDessert() { return new Tiramisu(); } }如果要添加同一个产品族的话,只需添加一个对应的甜品工厂类,满足开闭原则public abstract class Coffee { /** * 获取咖啡名字 * * @return */ public abstract String getName(); public void addSugar() { System.out.println("加糖"); } public void addMilk() { System.out.println("加奶"); } }public abstract class Dessert { /** * 展示 */ public abstract void show(); }public class Tiramisu extends Dessert { @Override public void show() { System.out.println("提拉米苏"); } } public class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }public class MatchaMousse extends Dessert { @Override public void show() { System.out.println("抹茶慕斯"); } } public class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }public class Client { public static void main(String[] args) { //意大利风味甜品工厂 ItalyDessertFactory factory = new ItalyDessertFactory(); //拿铁 Coffee coffee = factory.createCoffee(); //提拉米苏 Dessert dessert = factory.createDessert(); System.out.println(coffee.getName()); dessert.show(); } }优缺点当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象当产品族中需要增加一个新的产品时,所有的工厂类都需要需改使用场景当需要创建的对象是一系列相互关联或相互依赖的产品族时,如生产厂商的电视机、洗衣机、空调等系统中有多个产品族,但每次只使用其中的一个产品族,如某人只喜欢某一品牌的服装系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构,如输入法更换皮肤(4)模式扩展简单工厂 + 配置文件解耦在工厂类中加载配置文件的全类名,并创建对象进行存储,客户端如果需要对象,直接获取即可a. 定义配置文件bean.propertiesamerican=com.sw.设计模式.创建者模式.factory.configFactory.AmericanCoffee latte=com.sw.设计模式.创建者模式.factory.configFactory.LatteCoffeeb. 改进工厂类public class CoffeeFactory { //加载配置文件,获取配置文件中配置的全类名,并创建该类的对象进行存储 //1.定义容器对象存储咖啡 private static HashMap<String, Coffee> map = new HashMap<>(); //2.加载配置文件 static { //创建properties对象 Properties p = new Properties(); //调用load()方法进行加载 InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties"); try { p.load(is); //从p集合中获取全类名并创建对象 for (Object key : p.keySet()) { String className = p.getProperty((String) key); Class<?> clazz = Class.forName(className); Coffee coffee = (Coffee) clazz.newInstance(); //存储 map.put((String) key, coffee); } } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } /** * 根据名称获取对象 * * @param name 名称 * @return */ public static Coffee createCoffee(String name) { return map.get(name); } }使用静态成员变量来存储创建的对象,在静态代码块中读取配置文件并创建对象public class Client { public static void main(String[] args) { Coffee coffee = CoffeeFactory.createCoffee("american"); //美式咖啡 System.out.println(coffee.getName()); System.out.println("============================="); Coffee coffee1 = CoffeeFactory.createCoffee("latte"); //拿铁咖啡 System.out.println(coffee1.getName()); } }
2022年08月27日
36 阅读
0 评论
0 点赞
2022-08-27
创建者模式-单例模式
特点:将对象的创建与使用分离,可以降低系统的耦合度,使用者不需要关注对象的创建细节分为:单例模式、工厂模式、抽象工厂模式、原型模式、建造者模式1. 单例模式单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象单例模式的实现:饿汉式:类一加载就创建该实例对象懒汉式:需要使用时才创建该实例对象(1)饿汉式(静态变量方式)该方式在成员位置声明 Singleton 类型的静态变量,并创建 Singleton 类的对象 instance,instance 对象随着类的加载被创建,如果该类足够大且一直没有被使用的情况下会造成内存的浪费Singletonpublic class Singleton { //1.私有构造方法 private Singleton() { } //2.在本类中创建本类对象 private static Singleton instance = new Singleton(); //3.提供一个公共的访问方式,让外界获取该对象 public static Singleton getInstance() { return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); //true System.out.println(instance == instance1); } }(2)饿汉式(静态代码块方式)该方式在成员位置声明 Singleton 类型的静态变量,而对象的创建是在静态代码块中,也是随着类的加载而被创建,与静态变量方式类似Singletonpublic class Singleton { private Singleton() { } private static Singleton instance; static { instance = new Singleton(); } public static Singleton getInstance() { return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); //true System.out.println(instance == instance1); } }(3)懒汉式(线程不安全)当调用 getInstance() 方法获取 Singleton 类的对象的时候才创建 Singleton 类的对象,这样就实现了懒加载,但在多线程操作时存在线程不安全的问题Singletonpublic class Singleton { private Singleton() { } private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); //多线程操作时,存在线程不安全的问题 System.out.println(instance == instance1); } }(4)懒汉式(双重检测锁)使用 volatile 关键字保证可见性和防止指令重排(JVM在实例化对象时会进行优化和指令重排序操作,可能产生空指针)Singletonpublic class Singleton { private Singleton() { } //volatile保证可见性和防止指令重排 private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance == instance1); } }(5)懒汉式(静态内部类)实例由内部类创建,由于JVM在加载外部类的过程中不会加载静态内部类,只有内部类的属性/方法被调用时才会被加载,并初始化其静态属性,其中静态属性由于被 static 修饰,保证只被实例化一次,并且严格保证实例化顺序说明:第一次加载 Singleton 类时不会去初始化 INSTANCE,只有第一次调用 getInstance() 时,虚拟机加载 SingletonHolder 并初始化 INSTANCE ,这样既保证了现成安全,也保证了 Singleton 的唯一性,在没有加任何锁的情况下保证了线程的安全且不造成性能和内存的浪费(双重检测锁方式 和 静态内部类方式可以任选其一)Singlepublic class Singleton { private Singleton() { } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance == instance1); } }(6)枚举方式枚举是线程安全的,且只会被加载一次,注意枚举方式属于饿汉式Singletonpublic enum Singleton { INSTANCE; }Clientpublic class Client { public static void main(String[] args) { Singleton instance = Singleton.INSTANCE; Singleton instance1 = Singleton.INSTANCE; //true System.out.println(instance == instance1); } }(7)存在的问题破坏单例模式的方式:序列化和反序列化反射解决方法:序列化和反序列化 - 在单例类中添加 readResolve() 方法,在反序列化时,如果类中定义了这个方法,就返回这个方法的值,反之则创建新的对象反射 - 在单例类的构造方法中通过标志位来判断是否是第一次访问,且在该构造方法中需要加 synchronized 锁,锁该类 synchronized(Singleton.class)
2022年08月27日
46 阅读
0 评论
0 点赞
2022-08-27
合成复用原则
定义:尽量先使用组合或聚合等关联关系来实现,其次才考虑使用继承关系来实现类的复用通常分为:继承复用、合成复用继承复用破坏了类的封装性,将父类的实现细节暴露给了子类,父类对子类是透明的,这种复用又称为“白箱”复用耦合度高,父类的实现的任何变化都会导致子类的实现发生变化,不利于类的维护和扩展灵活性低,从父类继承而来的实现是静态的,在编译时已定义,所以在运行时不可能发生变化合成复用(可将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能)维持了类的封装性,因为成员对象的内部细节是新对象看不见的,所以又称为“黑箱”复用耦合度低,可以在类的成员位置声明抽象灵活性高,这种复用可以在运行时动态进行,新对象可以动态的引用与成员对象类型相同的对象以汽车分类管理为例:汽车按动力源可分为汽油车、新能源车;按颜色可分为白色、红色;如果同时考虑这两种成分,会产生多种组合可以看出使用继承复用会产生很多子类,如果要添加新的能源类型的车,就需要再定义新的类
2022年08月27日
48 阅读
0 评论
0 点赞
1
2
3
4