暑假持续学习中ing
【【狂神说Java】通俗易懂的23种设计模式教学(停更)-哔哩哔哩】
【狂神说笔记——23种设计模式】
只有七种
什么是设计模式

学习设计模式的意义
设计模式的本质是面向对象设计原则的实际运用, 是对类的封装性, 继承性和多态性以及类的关联关系和组合关系的充分理解
正确使用设计模式具有以下优点:
设计模式的基本要素
JUC并发编程【java提高】中详细的单例模式
饿汉式、DCL懒汉式
说到volatile的防止指令重排,那么volatile的内存屏障在哪里使用的最多,就是单例模式了。
1)饿汉式
饿汉式的问题:可能会浪费内存
饿汉式一上来就会把所有的东西加载到内存,对象就已经存在了,对象没有使用的话,可能会浪费内存
主要特点有:
构造函数私有,避免在外部被创建对象
提前创建好对象
提供公有的接口,返回在类内部提前创建好的对象
静态变量随着类的加载就已经实例化了,跟是否调用静态方法没有关系
饿汉式加载时就会初始化,懒汉式只有在获取单例的时候才会初始化
类加载时,成员变量会被初始化,局部变量不会
package com.kuang.single;
//饿汉式单例
public class Hungry {
//可能会浪费空间
private byte[] data1=new byte[1024*1024];
private byte[] data2=new byte[1024*1024];
private byte[] data3=new byte[1024*1024];
private byte[] data4=new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY=new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
2)DCL懒汉式
针对饿汉式单例的浪费内存的问题,提出了懒汉式单例,要用的时候再创建对象
package com.kuang.single;
//懒汉式单例
public class LazyMan {
private LazyMan(){
}
private static LazyMan lazyman;//还没有创建对象,只是声明,没有new
public static LazyMan getInstance(){
if(lazyman==null)
{
lazyman=new LazyMan();//如果这个对象为空,就实例化这个对象
}
return lazyman;
}
}
在多个线程的情况下,懒汉式单例可能会出现安全问题,就是线程1进入了if判断,并开始构造对象
package com.kuang.single;
//懒汉式单例
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static LazyMan lazyMan;
public static LazyMan getInstance(){
if (lazyMan==null){
lazyMan=new LazyMan();
}
return lazyMan;
}
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
可以看到,有2个线程调用了构造函数,这说明程序中现在有2个Lazyman对象,就不是单例了,所以不安全

双重锁机制
package com.kuang.single;
//懒汉式单例
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static LazyMan lazyMan;
//双重锁机制 DCL懒汉式
public static LazyMan getInstance(){
if (lazyMan==null){
synchronized (LazyMan.class){
if (lazyMan==null){
lazyMan=new LazyMan();
}
}
}
return lazyMan;
}
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
可以看到只创建了一个对象

但是还是有可能出现问题
创建对象的过程在极端情况下肯定是会出现问题的,因为不是原子性操作,会经历
1、分配内存空间,
2、执行构造方法(初始化对象)
3、把对象指向分配的空间
但是可能会发生指令重排,可能会按132的顺序执行,就是先分配内存空间,然后用空对象先占用内存空间,占用之后再执行构造方法
如下图,很有可能A执行了13还没执行2,但是现在lazyman已经不是null了,如果现在进来一个B线程,外层判断不为空,那么B线程会直接返回lazyman,但lazyman实际上还没有完成构造,所以不安全(new只是把应用加上了,但是堆还没有创建完,return就会有问题)

所以要用volatile修饰防止指令重排(防止第二个线程抢先执行,抢先返回一个尚未初始化完成的引用)
所以这里是同步代码块保证了操作的原子性,volatile禁止了指令重排
指令重排的原理是为了提升CPU多段流水的效率,但并不是指令任意重排,处理器必须能正确处理指令依赖关系保障程序得出正确的执行结果。
总结:synchronized保证的是if判断和new一个对象能同时成功或同时失败,但是new一个对象不是原子操作,执行13后,第二个线程认为已经new对象成功了,最上面的if判断不等于null
3)静态内部类
在一个类里面写一个静态的类
首先只要单例一定要先构造器私有
加载外部类时,不会加载静态内部类
线程安全且懒加载
但是静态内部类单例也是不安全的,因为反射可以破坏单例
//静态内部类
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.holder;
}
public static class InnerClass{
private static final Holder holder = new Holder();
}
}
测试:
package com.kuang.single;
//静态内部类
public class Holder {
private Holder(){
System.out.println(Thread.currentThread().getName()+"OK");
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER=new Holder();
}
public static void main(String[] args) {
for(int i=0;i<10;i++)
{
new Thread(()->{
Holder.getInstance();
}).start();
}
}
}
可以看到,内存中只有一个实例,就是只有一个线程进入了构造函数,因为静态类只加载一次

单例不安全,因为反射
但是只要有反射,任何私有的都是纸老虎,我们以DCL的单例为例,来试试反射
//反射!
public static void main(String[] args) throws Exception {
LazyMan instance = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
结果:

可以破解:
private LazyMan(){
synchronized (LazyMan.class){
if (lazyMan!=null){
throw new RuntimeException("不用试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName()+"ok");
}
结果:

相当于在DCL的基础上又在构造函数里面加了一重检测
完整代码如下:
package com.kuang.single;
import java.lang.reflect.Constructor;
//懒汉式单例
public class LazyMan {
private LazyMan(){
synchronized (LazyMan.class){
if (lazyMan!=null){
throw new RuntimeException("不用试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static LazyMan lazyMan;
//双重锁机制 DCL懒汉式
public static LazyMan getInstance(){
if (lazyMan==null){
synchronized (LazyMan.class){
if (lazyMan==null){
lazyMan=new LazyMan();
/**
* 1、分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向这个空间
*
* 123
* 132 A
* B
*/
}
}
}
return lazyMan;
}
// //多线程并发
// public static void main(String[] args) {
// for (int i = 0; i < 10; i++) {
// new Thread(()->{
// LazyMan.getInstance();
// }).start();
// }
// }
//反射!
public static void main(String[] args) throws Exception {
LazyMan instance = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
}
现在我们不用getInstance()去获取对象,而是直接通过反射创建两个对象
//反射!
public static void main(String[] args) throws Exception {
// LazyMan instance = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance2 = declaredConstructor.newInstance();
LazyMan instance = declaredConstructor.newInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
可以发现,单例又被破坏了,
因为构造函数里面判断的是

但是注意,我们用反射new 的对象跟类里面的lazyman对象肯定是不一样的啊,没有调用getInstance(),类里面的lazyman就一直为空,所以单例又被破坏了

解决方法,用个标志位
private static boolean flag=false;
private LazyMan(){
synchronized (LazyMan.class){
if (flag==false){
flag=true;
}else {
throw new RuntimeException("不用试图使用反射破坏异常");
}
// if (lazyMan!=null){
// throw new RuntimeException("不用试图使用反射破坏异常");
// }
}
System.out.println(Thread.currentThread().getName()+"ok");
}

但是,再牛逼的加密也会解密
来我们继续破坏单例,我们把这个flag字段给它破坏了
//反射!
public static void main(String[] args) throws Exception {
// LazyMan instance = LazyMan.getInstance();
Field flag = LazyMan.class.getDeclaredField("flag");
flag.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance = declaredConstructor.newInstance();
flag.set(instance,false);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
结果:可以发现单例又被破坏了

完整代码:
package com.kuang.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
//懒汉式单例
public class LazyMan {
private static boolean flag=false;
private LazyMan(){
synchronized (LazyMan.class){
if (flag==false){
flag=true;
}else {
throw new RuntimeException("不用试图使用反射破坏异常");
}
// if (lazyMan!=null){
// throw new RuntimeException("不用试图使用反射破坏异常");
// }
}
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static LazyMan lazyMan;
//双重锁机制 DCL懒汉式
public static LazyMan getInstance(){
if (lazyMan==null){
synchronized (LazyMan.class){
if (lazyMan==null){
lazyMan=new LazyMan();
/**
* 1、分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向这个空间
*
* 123
* 132 A
* B
*/
}
}
}
return lazyMan;
}
// //多线程并发
// public static void main(String[] args) {
// for (int i = 0; i < 10; i++) {
// new Thread(()->{
// LazyMan.getInstance();
// }).start();
// }
// }
//反射!
public static void main(String[] args) throws Exception {
// LazyMan instance = LazyMan.getInstance();
Field flag = LazyMan.class.getDeclaredField("flag");
flag.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance = declaredConstructor.newInstance();
flag.set(instance,false);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
}
那怎么解决呢?我们点进去反射的newInstance()看看呢
我们可以看到,如果类是一个枚举类型的话,就会告诉你不能使用反射破坏枚举,枚举是jdk 1.5 开始出现的,自带单例模式

4)枚举
枚举本身也是一个类
package com.kuang.single;
//enum 是一个什么? 本身也是一个Class类
public enum EnumSingle {
INSTANCE;
public static EnumSingle getInstance()
{
return INSTANCE;
}
}
class Test{
public static void main(String[] args) {
EnumSingle instance1=EnumSingle.INSTANCE;
EnumSingle instance2=EnumSingle.INSTANCE;
EnumSingle instance3=EnumSingle.getInstance();
System.out.println(instance1);
System.out.println(instance2);
System.out.println(instance3);
}
}

我们来试试用反射破坏枚举单例

package com.kuang.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//enum 是一个什么? 本身也是一个Class类
public enum EnumSingle {
INSTANCE;
public static EnumSingle getInstance()
{
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
EnumSingle instance1=EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
下面的错误提示是枚举类没有空参的构造方法
也就是下面这句话出错了idea骗了我们
//NoSuchMethodException: com.kuang.single.EnumSingle.()
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
正常破坏单例是应该报错不能使用反射破坏枚举

通过反编译我们可以看到,这个枚举本身也是一个class,它继承了一个枚举类
然而构造器还是空参的啊,说明我们还是被骗了

现在我们用jad.exe反编译试试
下载地址
Java反编译工具Jad的使用
jad.exe复制到.class文件夹下

我们把class字节码生成java文件看看

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumSingle.java
package com.kuang.single;
public final class EnumSingle extends Enum
{
public static EnumSingle[] values()
{
return (EnumSingle[])$VALUES.clone();
}
public static EnumSingle valueOf(String name)
{
return (EnumSingle)Enum.valueOf(com/kuang/single/EnumSingle, name);
}
private EnumSingle(String s, int i)
{
super(s, i);
}
public static EnumSingle getInstance()
{
return INSTANCE;
}
public static final EnumSingle INSTANCE;
private static final EnumSingle $VALUES[];
static
{
INSTANCE = new EnumSingle("INSTANCE", 0);
$VALUES = (new EnumSingle[] {
INSTANCE
});
}
}
可以看到,不是无参构造器哦,而是有参构造器,有一个String,一个Int

现在我们修改反射代码
// Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);

完整代码:
package com.kuang.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//enum 是一个什么? 本身也是一个Class类
public enum EnumSingle {
INSTANCE;
public static EnumSingle getInstance()
{
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
EnumSingle instance1=EnumSingle.INSTANCE;
//NoSuchMethodException: com.kuang.single.EnumSingle.()
// Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
作用:
OOP七大原则
核心本质
实例化对象不使用new, 用工厂方法代替
将选择实现类, 创建对象统一管理和控制. 从而将调用者跟我们的实现类解耦
三种模式:
简单工厂模式
工厂方法模式
抽象工厂模式
factory/simple
Car
package factory.simple;
public interface Car {
void name();
}
WuLing
package factory.simple;
public class Wuling implements Car{
@Override
public void name() {
System.out.println("五菱宏光!");
}
}
Tesla
package factory.simple;
public class Tesla implements Car{
@Override
public void name() {
System.out.println("特斯拉!");
}
}
原来的方法
还需要我们自己把车建出来
Consumer
package factory.simple;
public class Consumer {
public static void main(String[] args) {
//接口,所有的实现类!工厂
Car car =new Wuling();
Car car2 =new Tesla();
car.name();
car2.name();
}
}
CarFactory
package factory.simple;
public class CarFactory {
public static Car getCar(String car){
if (car.equals("五菱")){
return new Wuling();
}else if (car.equals("特斯拉")){
return new Tesla();
}else {
return null;
}
}
}
现在的方法
Consumer
package factory.simple;
public class Consumer {
public static void main(String[] args) {
//接口,所有的实现类!工厂
// Car car =new Wuling();
// Car car2 =new Tesla();
//2.使用工厂创建
Car car = CarFactory.getCar("五菱");
Car car2 = CarFactory.getCar("特斯拉");
car.name();
car2.name();
}
}
但是
我们现在在加一个车
Dazhong
package factory.simple;
public class Dazhong implements Car{
@Override
public void name() {
System.out.println("大众");
}
}
我们就需要在工厂中在加一个if else语句来实现!!!

我们会想到方法二

//方法二
public static Car getWuling(){
return new Wuling();
}
public static Car getTesla(){
return new Tesla();
}
但是,还是需要改变原有代码
所以,简单工厂模式还叫静态工厂模式
//静态工厂模式
//增加一个新的产品,如果你不修改代码,做不到!
这就有了工厂方法模式
图解

factory/method
Car
package factory.method;
public interface Car {
void name();
}
WuLing
package factory.method;
public class Wuling implements Car {
@Override
public void name() {
System.out.println("五菱宏光!");
}
}
Tesla
package factory.method;
public class Tesla implements Car {
@Override
public void name() {
System.out.println("特斯拉!");
}
}
把CarFactory也改成接口
CarFactory
package factory.method;
//工厂方法模式
public interface CarFactory {
Car getCar();
}
对于每个车,自己都建造工厂
WulingFactory
package factory.method;
public class WulingFactory implements CarFactory{
@Override
public Car getCar() {
return new Wuling();
}
}
TeslaFactory
package factory.method;
public class TeslaFactory implements CarFactory{
@Override
public Car getCar() {
return new Tesla();
}
}
Consumer
package factory.method;
public class Consumer {
public static void main(String[] args) {
Car car = new WulingFactory().getCar();
Car car2 = new TeslaFactory().getCar();
car.name();
car2.name();
}
}
这时候,我们如果有新车的话
MoBai
package factory.method;
public class MoBai implements Car{
@Override
public void name() {
System.out.println("摩拜单车");
}
}
这时候,我们只需要建个对应的工厂就好了
package factory.method;
public class MoBaiFactory implements CarFactory{
@Override
public Car getCar() {
return new MoBai();
}
}
Consumer
Car car3 = new MoBaiFactory().getCar();
car3.name();
但是,我们发现我们每多一个需求,就需要扩展一个工厂类
这样工厂类,就会越来越庞大
我们有了抽象工厂模式
图解

对比
//结构复杂度: simple
//代码复杂度: simple
//编程复杂度: simple
//管理上的复杂度: simple
//根据设计原则:工厂方法模式!
//根据实际业务:简单工厂模式!
定义︰抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类
适用场景:
优点:
缺点:
图解


factory/abstract1
两个产品接口
IphoneProduct
package factory.abstract1;
//手机产品接口
public interface IphoneProduct {
void start();
void shutdown();
void callup();
void sendSMS();
}
IRouterProduct
package factory.abstract1;
//路由器产品接口
public interface IRouterProduct {
void start();
void shutdown();
void openWifi();
void setting();
}
同一产品等级的两个工厂
XiaomiPhone
package factory.abstract1;
//小米手机
public class XiaomiPhone implements IPhoneProduct{
@Override
public void start() {
System.out.println("小米开机");
}
@Override
public void shutdown() {
System.out.println("小米关机");
}
@Override
public void callup() {
System.out.println("小米打电话");
}
@Override
public void sendSMS() {
System.out.println("小米发信息");
}
}
HuaweiPhone
package factory.abstract1;
//华为手机
public class HuaweiPhone implements IPhoneProduct{
@Override
public void start() {
System.out.println("华为开机");
}
@Override
public void shutdown() {
System.out.println("华为关机");
}
@Override
public void callup() {
System.out.println("华为打电话");
}
@Override
public void sendSMS() {
System.out.println("华为发信息");
}
}
小米产品族的路由器
XiaomiRouter
package factory.abstract1;
//小米路由器
public class XiaomiRouter implements IRouterProduct{
@Override
public void start() {
System.out.println("小米开启路由器");
}
@Override
public void shutdown() {
System.out.println("小米关闭路由器");
}
@Override
public void openWifi() {
System.out.println("小米开启Wifi");
}
@Override
public void setting() {
System.out.println("小米设置路由器");
}
}
华为产品族的路由器
package factory.abstract1;
//华为路由器
public class HuaweiRouter implements IRouterProduct{
@Override
public void start() {
System.out.println("华为开启路由器");
}
@Override
public void shutdown() {
System.out.println("华为关闭路由器");
}
@Override
public void openWifi() {
System.out.println("华为开启Wifi");
}
@Override
public void setting() {
System.out.println("华为设置路由器");
}
}
然后,我们需要工厂来建造产品
IProductFactory
抽象工厂:工厂的工厂
具体工厂需要实现它
package factory.abstract1;
//抽象产品工厂
public interface IProductFactory {
//生产手机
IPhoneProduct iPhoneProduct();
//生产路由器
IRouterProduct iRouterProduct();
}
XiaomiFactory
小米工厂
package factory.abstract1;
public class XiaomiFactory implements IProductFactory{
@Override
public IPhoneProduct iPhoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new XiaomiRouter();
}
}
HuaweiFactory
华为工厂
package factory.abstract1;
public class HuaweiFactory implements IProductFactory{
@Override
public IPhoneProduct iPhoneProduct() {
return new HuaweiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new HuaweiRouter();
}
}
Client
编写客户端测试
package factory.abstract1;
public class Client {
public static void main(String[] args) {
System.out.println("=================小米系列产品==============");
XiaomiFactory xiaomiFactory = new XiaomiFactory();
IPhoneProduct iPhoneProduct = xiaomiFactory.iPhoneProduct();
iPhoneProduct.start();
IRouterProduct iRouterProduct = xiaomiFactory.iRouterProduct();
iRouterProduct.start();
System.out.println("=================华为系列产品==============");
HuaweiFactory huaweiFactory = new HuaweiFactory();
iPhoneProduct = huaweiFactory.iPhoneProduct();
iPhoneProduct.start();
iRouterProduct = huaweiFactory.iRouterProduct();
iRouterProduct.start();
//=================小米系列产品==============
//小米开机
//小米开启路由器
//=================华为系列产品==============
//华为开机
//华为开启路由器
}
}
对应类图

如果现在加一个产品笔记本
需要改动抽象工厂及其所有子类
违反了开闭原则
如果没有改动,还是可以接受的
抽象工厂关注产品簇
简单工厂模式(静态工厂模式)
工厂方法模式
抽象工厂模式
应用场景
建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式。
定义︰将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
例子:
角色分析

同中步骤可以造出来不同房子
Product
产品:房子
package builder;
//产品:房子
public class Product {
private String buildA;
private String buildB;
private String buildC;
private String buildD;
public String getBuildA() {
return buildA;
}
public void setBuildA(String buildA) {
this.buildA = buildA;
}
public String getBuildB() {
return buildB;
}
public void setBuildB(String buildB) {
this.buildB = buildB;
}
public String getBuildC() {
return buildC;
}
public void setBuildC(String buildC) {
this.buildC = buildC;
}
public String getBuildD() {
return buildD;
}
public void setBuildD(String buildD) {
this.buildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"buildA='" + buildA + '\'' +
", buildB='" + buildB + '\'' +
", buildC='" + buildC + '\'' +
", buildD='" + buildD + '\'' +
'}';
}
}
Builder
抽象的建造者
package builder;
//抽象的建造者:方法
public abstract class Builder {
abstract void buildA();//地基
abstract void buildB();//钢筋工程
abstract void buildC();//铺电线
abstract void buildD();//粉刷
//完工:得到产品
abstract Product getProduct();
}
Worker
具体的建造者:工人
注意:产品是工人创建的

package builder;
public class Worker extends Builder {
private Product product;
public Worker() {
product = new Product();
}
@Override
void buildA() {
product.setBuildA("地基");
System.out.println("地基");
}
@Override
void buildB() {
product.setBuildB("钢筋工程");
System.out.println("钢筋工程");
}
@Override
void buildC() {
product.setBuildC("铺电线");
System.out.println("铺电线");
}
@Override
void buildD() {
product.setBuildD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
没有指挥工人
Director
指挥
package builder;
//指挥:核心,负责构建一个工程
//工程如何构建,有它绝决定
public class Director {
//指挥工人按照顺序建房子
public Product build(Builder builder){
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
Test
测试
package builder;
public class Test {
public static void main(String[] args) {
//指挥
Director director=new Director();
//指挥具体的工人完成产品
Product build = director.build(new Worker());
System.out.println(build.toString());
//地基
//钢筋工程
//铺电线
//粉刷
//Product{buildA='地基', buildB='钢筋工程', buildC='铺电线', buildD='粉刷'}
}
}
builer/demo02
Product
package builder.demo02;
//产品:套餐
public class Product {
private String BuildA ="汉堡";
private String BuildB ="可乐";
private String BuildC ="薯条";
private String BuildD ="甜点";
public String getBuildA() {
return BuildA;
}
public void setBuildA(String buildA) {
BuildA = buildA;
}
public String getBuildB() {
return BuildB;
}
public void setBuildB(String buildB) {
BuildB = buildB;
}
public String getBuildC() {
return BuildC;
}
public void setBuildC(String buildC) {
BuildC = buildC;
}
public String getBuildD() {
return BuildD;
}
public void setBuildD(String buildD) {
BuildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"BuildA='" + BuildA + '\'' +
", BuildB='" + BuildB + '\'' +
", BuildC='" + BuildC + '\'' +
", BuildD='" + BuildD + '\'' +
'}';
}
}
Builder
不赋值,就是默认的4件套餐
package builder.demo02;
//建造者
public abstract class Builder {
abstract Builder BuildA(String msg);//"汉堡";
abstract Builder BuildB(String msg);//"可乐";
abstract Builder BuildC(String msg);//"薯条";
abstract Builder BuildD(String msg);//"甜点";
abstract Product getProduct();
}
Worker
package builder.demo02;
//具体的建造者
public class Worker extends Builder{
private Product product;
public Worker() {
product = new Product();
}
@Override
Builder BuildA(String msg) {
product.setBuildA(msg);
return this;
}
@Override
Builder BuildB(String msg) {
product.setBuildB(msg);
return this;
}
@Override
Builder BuildC(String msg) {
product.setBuildC(msg);
return this;
}
@Override
Builder BuildD(String msg) {
product.setBuildD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
Test
package builder.demo02;
public class Test {
public static void main(String[] args) {
//服务员
Worker worker=new Worker();
//链式编程
// Product product = worker.getProduct();
// System.out.println(product.toString());
//Product{BuildA='汉堡', BuildB='可乐', BuildC='薯条', BuildD='甜点'}
//链式编程:在原来的基础上可以自由组合,如果不组合,也有默认的套餐
Product product = worker.BuildA("全家桶").BuildB("雪碧").getProduct();
System.out.println(product.toString());
//Product{BuildA='全家桶', BuildB='雪碧', BuildC='薯条', BuildD='甜点'}
}
}
模式意图
将一个复杂的构件与其表示相分离,使得同样的构件过程可以创建不同的表示
使用场景
Builder
抽象建造者,给出一个抽象接口, 以规范产品对象的各个组成成分的建造. 这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建
ConcreteBuilder
实现Builder接口, 针对不同的商业逻辑, 具体化复杂对象的各部分的创建, 即具体建造者
Director
指挥者, 调用具体建造者来创建复杂对象的各个部分, 在指导者不涉及具体产品的信息, 只负责保证对象各部分完整创建或者按某种顺序创建
Product
要创建的复杂对象, 即产品角色

Prototype
Cloneable接口
clone()方法
phototype/demo01
Video
package phototype.demo01;
import java.util.Date;
/*
1..实现一个接口 Cloneable
2.重写一个方法 clone()
*/
//Video:视频的类
public class Video implements Cloneable{//无良up主,克隆别人的视频
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Video() {
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", createTime=" + createTime +
'}';
}
}
Bilibili
package phototype.demo01;
import java.util.Date;
/*
客户端:克隆
*/
public class Bilibili {
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象v1
Date date = new Date();
Video v1 = new Video("狂神说Java", date);
System.out.println("v1=>" + v1);
System.out.println("v1=>hash:" + v1.hashCode());
//v1克隆v2
//Video v2 = new Video( "狂神说Java", date);
Video v2 = (Video) v1.clone();
System.out.println("v2=>" + v2);
System.out.println("v2=>hash:" + v2.hashCode());
//v1=>Video{name='狂神说Java', createTime=Tue Jul 19 19:25:31 CST 2022}
//v1=>hash:1735600054
//v2=>Video{name='狂神说Java', createTime=Tue Jul 19 19:25:31 CST 2022}
//v2=>hash:21685669
v2.setName("Clone:狂神说Java");
System.out.println("v2" + v2);
}
}
v2=>v1
浅克隆
同时指向同一个date

测试
System.out.println("==============");
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
System.out.println("==============");
date.setTime(22131231);
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);

修改了v1的date,v2也改变其date了
我们想要v2也有自己的date属性
深克隆
一种实现方法时:改造克隆方法
另外还有:序列化、反序列化

复制代码到demo02
改造克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
//实现深克隆~ 序列化, 反序列化
Video v=(Video) obj;
v.createTime = (Date) this.createTime.clone(); //将这个对象的属性也进行克隆
return v;
}
Video
package phototype.demo02;
import java.util.Date;
/*
1..实现一个接口 Cloneable
2.重写一个方法 clone()
*/
//Video:视频的类
public class Video implements Cloneable{//无良up主,克隆别人的视频
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
//实现深克隆~ 序列化, 反序列化
Video v=(Video) obj;
v.createTime = (Date) this.createTime.clone(); //将这个对象的属性也进行克隆
return v;
}
public Video() {
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", createTime=" + createTime +
'}';
}
}
Bilibili
测试
package phototype.demo02;
import java.util.Date;
//Spring Bean :单例模式 原型模式
//原型模式+工厂模式==> new <=>原型模式
/*
客户端:克隆
*/
public class Bilibili {
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象v1
Date date = new Date();
Video v1 = new Video("狂神说Java", date);
//v1克隆v2
Video v2 = (Video) v1.clone();
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
System.out.println("==============");
date.setTime(22131231);
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
}
}

2022/7/19 20:00:00
p1~p7
2022/7/20 09:00:00
作用

分类
适配器模式就像USB网线转换器

Adaptee
package adapter;
//要被适配的类:网线
public class Adaptee {
public void request() {
System.out.println("连接网线上网");
}
}
面向接口编程
抽象的适配器
NetToUsb
package adapter;
//接口转换器的抽象实现~
public interface NetToUsb {
//作用:处理请求,网线=>usb
public void handleRequest();
}
具体的适配器
使用继承来实现的
Adapter
package adapter;
//1.继承(类适配器,单继承)
//真正的适配器,需要连接USB,连接网线~
public class Adapter extends Adaptee implements NetToUsb {
@Override
public void handleRequest() {
//上网的具体实现,找一个转接头
super.request();
}
}
Computer
package adapter;
//客户端类: 想上网,插不网线~
public class Computer {
//我们的电脑需要连接:找一个转换器才可以上网
public void net(NetToUsb adapter) {
//上网的具体实现, 找个转换器
adapter.handleRequest();
}
public static void main(String[] args) {
//Adapter继承关系实现
//电脑,适配器,网线~
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter adapter = new Adapter(); //转按器
computer.net(adapter);
}
}
具体的适配器
使用组合来实现的
Adapter2
package adapter;
//2.组合(对象适配器,常用)
//真正的适配器,需要连接USB,连接网线~
public class Adapter2 implements NetToUsb{
//组合模式
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
//上网的具体实现,找一个转接头
adaptee.request();//可以上网
}
}
Computer.main()
System.out.println("++++++++++++++++++++++++++++++");
//电脑,适配器,网线~
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter2 adapter = new Adapter2(adaptee); //转换器
computer.net(adapter);
再理解
图解

又理解
单一职责原则


与抽象工厂模式对比
可以处理多种维度扩展的情况
结构型模式
抽象的品牌
Brand
package bridge;
//品牌
public interface Brand {
void info();
}
具体的品牌
Lenovo
package bridge;
//联想品牌
public class Lenovo implements Brand {
@Override
public void info() {
System.out.print("联想");
}
}
Apple
package bridge;
//苹果品牌
public class Apple implements Brand {
@Override
public void info() {
System.out.print("苹果");
}
}
Computer
package bridge;
//抽象的电脑类型类
public abstract class Computer {
//组合,品牌~ 桥
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void info() {
brand.info();//自带品牌
}
}
class Desktop extends Computer {
public Desktop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("台式机");
}
}
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("笔记本");
}
}
Test
package bridge;
public class Test {
public static void main(String[] args) {
//苹果管记本
Computer computer = new Laptop(new Apple());
computer.info();
System.out.println("========");
//联想台式机
Computer computer2 = new Desktop(new Lenovo());
computer2.info();
//苹果笔记本
//=======
//联想台式机
}
}
图解

优劣势分析
是SpringAOP的底层 [SpringAOP和SpringMVC]
代理模式的分类
中介

角色分析:
proxy/demo01
抽象角色
Rent
package proxy.demo01;
//抽象角色:租房
public interface Rent {
public void rent();
}
真实角色
Host
package proxy.demo01;
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子");
}
}
代理角色
Proxy
package proxy.demo01;
//代理
public class Proxy implements Rent{
private Host host;
public Proxy(){
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
host.rent();
seeHouse();
hetong();
fare();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
//签合同
public void hetong(){
System.out.println("签合同");
}
}
Client
package proxy.demo01;
public class Client {
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
// host.rent();
//代理,中介帮房东租房子,但是 代理一般会有一些附属操作
Proxy proxy = new Proxy(host);
//不用面对房东,直接找中介租房即可
proxy.rent();
//房东要出租房子
//中介带你看房
//签合同
//收中介费
}
}
代理模式的好处:
缺点:
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
聊聊AOP:纵向开发,横向开发。
图解

proxy/demo02
UserService
package proxy.demo02;
//抽象角色:增删改查业务
public interface UserService {
void add();
void delete();
void update();
void query();
}
UserServiceImpl
package proxy.demo02;
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
思路1 :在实现类上增加代码 【麻烦!】

思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!
UserServiceProxy
package proxy.demo02;
//代理角色,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
Client
package proxy.demo02;
public class Client {
public static void main(String[] args) {
//真实业务
UserServiceImpl userService = new UserServiceImpl();
// userService.add();
//代理类
UserServiceProxy proxy = new UserServiceProxy();
//使用代理类实现日志功能!
proxy.setUserService(userService);
proxy.add();
}
}
需要了解的两个类: Proxy: 代理, InvocationHandler: 调用处理程序
Proxy



InvocationHandler(调用处理程序)

Rent
package proxy.demo03;
//抽象角色:租房
public interface Rent {
public void rent();
}
Host
package proxy.demo03;
//被代理角色:房东
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子");
}
}
ProxyInvocationHandler
package proxy.demo03;
//ProxyInvocationHandler. java 即代理角色
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client
package proxy.demo03;
//租客
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//将真实角色放置进去!
pih.setRent(host);
//动态生成对应的代理类!
Rent proxy = (Rent)pih.getProxy();
//执行方法
proxy.rent();
//带房客看房
//房东要出租房子
//收中介费
}
}
我们来使用动态代理实现代理我们后面写的UserService!
我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!
ProxyInvocationHandler
package proxy.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理对象
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// proxy : 代理类
// method : 代理类的调用处理程序的方法对象.
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
log(method.getName());
//动态代理的本质,就是使用反射机制实现
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
Client
package proxy.demo04;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService); //设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
//执行了add方法
//增加了一个用户
}
}
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
2022/7/22 11:41:01 星期三
Markdown 40419 字数 2848 行数
HTML 35124 字数 1863 段落