学习设计模式的意义
Gof23
创建型模式:
结构型模式:
行为型模式:
饿汉式、DCL懒汉式,深究
饿汉式
//饿汉式单例
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;
}
}
懒汉式
存在多线程并发模式,后面的DCL懒汉式解决并发问题
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"OK");
}
private static LazyMan lazyMan;
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
lazyMan = new LazyMan();//不是一个原子性操作
}
return lazyMan;
}
/*
* 1.分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向者个空间
*
* 123
* 132 A
*
* B //此时lazyMan还没有完成构造
*
* */
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
DCL懒汉式
注意:synchronized 解决并发问题,但是因为lazyMan = new LazyMan();
不是原子性操作(可以分割,见代码注释),可能发生指令重排序的问题,通过volatil来解决
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"OK");
}
private volatile static LazyMan lazyMan;
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){//synchronized加锁解决多线程下的问题
if(lazyMan == null){
lazyMan = new LazyMan();//不是一个原子性操作
}
}
}
return lazyMan;
}
/*
* 1.分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向者个空间
*
* 123
* 132 A
*
* B //此时lazyMan还没有完成构造
*
* */
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
静态内部类
//静态内部类
public class Holder {
//构造器私有
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
单例不安全,反射破坏(见注释及main方法中反射破解步骤)
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
//单例懒汉式
//懒汉式单例
public class LazyMan {
private static boolean qingjiang = false;//红绿等解决通过反射创建对象(反编译可以破解该方法)
private LazyMan(){
synchronized (LazyMan.class){
if (qingjiang==false){
qingjiang = true;
}else{
throw new RuntimeException("不要试图使用反射破坏单例");
}
}
System.out.println(Thread.currentThread().getName()+"OK");
}
private volatile static LazyMan lazyMan;//volatile避免指令重排
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
lazyMan = new LazyMan();//不是一个原子性操作
}
return lazyMan;
}
//反射!
public static void main(String[] args) throws Exception {
//LazyMan instance = LazyMan.getInstance();
Field qingjiang = LazyMan.class.getDeclaredField("qingjiang");
qingjiang.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);//无视私有的构造器
LazyMan instance1 = declaredConstructor.newInstance();
qingjiang.set(instance1,false);
System.out.println(instance1);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance2);
}
/*
* 1.分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向者个空间
*
* 123
* 132 A
*
* B //此时lazyMan还没有完成构造
*
* */
//多线程并发
/* public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}*/
}
枚举: 通过反射破解枚举发现不成功:
1、普通的反编译会欺骗开发者,说enum枚举是无参构造
2、实际enum为有参构造(见后面);
3、通过反射破解枚举会发现抛出异常
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.ph.single.Test.main(EnumSingle.java:19)
import java.lang.reflect.Constructor;
//enmu是什么?本身也是一个class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
//java.lang.NoSuchMethodException: com.ph.single.EnumSingle.()
System.out.println(instance);
System.out.println(instance2);
}
}
通过idea和jdk自带的反编译枚举如下:
通过jad反编译枚举的代码如下
发现枚举是有参构造
作用:
OOP七大原则
核心本质
三种模式:
Car
package com.kuang.factory.simple;
public interface Car {
void name();
}
123456
Tesla
package com.kuang.factory.simple;
public class Tesla implements Car {
public void name() {
System.out.println("特斯拉");
}
}
12345678
WuLing
package com.kuang.factory.simple;
public class WuLing implements Car {
public void name() {
System.out.println("五菱宏光");
}
}
1234567
CarFactory
package com.kuang.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;
}
//方法二
public static Car getWuLing(){
return new WuLing();
}
public static Car getTesla(){
return new Tesla();
}
}
12345678910111213141516171819202122232425
Consumer
package com.kuang.factory.simple;
public class Consumer {
public static void main(String[] args) {
//接口,所有实现类
Car wuLing = new WuLing();
Car tesla = new Tesla();
wuLing.name();
tesla.name();
wuLing=CarFactory.getCar("五菱宏光");
tesla=CarFactory.getCar("特斯拉");
wuLing.name();
tesla.name();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pnv3vWzh-1615121940899)(C:\Users\MengFei\AppData\Roaming\Typora\typora-user-images\image-20210218170526439.png)]
Car
package com.kuang.factory.method;
public interface Car {
void name();
}
123456
CarFactory
package com.kuang.factory.method;
public interface CarFactory {
//工厂方法模式
Car getCar();
}
1234567
Tesla
package com.kuang.factory.method;
public class Tesla implements Car {
public void name() {
System.out.println("特斯拉");
}
}
12345678
TeslaFactory
package com.kuang.factory.method;
public class TeslaFactory implements CarFactory {
public Car getCar() {
return new Tesla();
}
}
12345678
WuLing
package com.kuang.factory.method;
public class WuLing implements Car {
public void name() {
System.out.println("五菱宏光");
}
}
12345678
WuLingFactory
package com.kuang.factory.method;
public class WuLingFactory implements CarFactory {
public Car getCar() {
return new WuLing();
}
}
12345678
Consumer
package com.kuang.factory.method;
import com.kuang.factory.simple.CarFactory;
import com.kuang.factory.simple.Tesla;
import com.kuang.factory.simple.WuLing;
public class Consumer {
public static void main(String[] args) {
//接口,所有实现类
Car wuLing = new WuLingFactory().getCar();
Car tesla = new TeslaFactory().getCar();
wuLing.name();
tesla.name();
}
//结构复杂度: simple
//代码复杂度: simple
//编程复杂度: simple
//管理上的复杂度: simple
//舰据设计原则:工厂方法模式!
//根据实际业务:简单工厂模式!
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nuIPsz8-1615121940901)(C:\Users\MengFei\AppData\Roaming\Typora\typora-user-images\image-20210218170437446.png)]
代码测试
IPhoneProduct
package com.kuang.factory.abstract1;
//手机产品接口
public interface IPhoneProduct {
void start();
void shutdown();
void call();
void sendMsg();
}
12345678910
IRouterProduct
package com.kuang.factory.abstract1;
//路由器产品接口
public interface IRouterProduct {
void start();
void shutdown();
void openWifi();
void setting();
}
123456789
IProductFactory
package com.kuang.factory.abstract1;
//抽象产品工厂
public interface IProductFactory {
//生产手机
IPhoneProduct iPhoneProduct();
//生产路由器
IRouterProduct iRouterProduct();
}
12345678910
XiaomiPhone
package com.kuang.factory.abstract1;
public class XiaomiPhone implements IPhoneProduct {
@Override
public void start() {
System.out.println("小米开机");
}
@Override
public void shutdown() {
System.out.println("小米关机");
}
@Override
public void call() {
System.out.println("小米打电话");
}
@Override
public void sendMsg() {
System.out.println("小米发信息");
}
}
123456789101112131415161718192021222324
XiaomiRouter
package com.kuang.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("小米设置路由器");
}
}
123456789101112131415161718192021222324
XiaomiFactory
package com.kuang.factory.abstract1;
public class XiaomiFactory implements IProductFactory {
@Override
public IPhoneProduct iPhoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new XiaomiRouter();
}
}
1234567891011121314
Client
package com.kuang.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();
}
}
1234567891011121314
运行结果
=================小米系列产品==============
小米开机
小米开启路由器
应用场景
建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式。
定义︰将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
例子:
角色分析
既然是建造者模式,那么我们还是继续造房吧,其实我也想不到更简单的例子。假设造房简化为如下步骤:(1)地基(2)钢筋工程(3)铺电线(4)粉刷;“如果”要盖一座房子,首先要找一个建筑公司或工程承包商(指挥者)。承包商指挥工人(具体建造者)过来造房子(产品),最后验收。
Product
package com.kuang.builder;
//产品,房子
public class Product {
private String builderA;
private String builderB;
private String builderC;
private String builderD;
public String getBuilderA() {
return builderA;
}
public void setBuilderA(String builderA) {
this.builderA = builderA;
}
public String getBuilderB() {
return builderB;
}
public void setBuilderB(String builderB) {
this.builderB = builderB;
}
public String getBuilderC() {
return builderC;
}
public void setBuilderC(String builderC) {
this.builderC = builderC;
}
public String getBuilderD() {
return builderD;
}
public void setBuilderD(String builderD) {
this.builderD = builderD;
}
@Override
public String toString() {
return "Product{" +
"builderA='" + builderA + '\'' +
", builderB='" + builderB + '\'' +
", builderC='" + builderC + '\'' +
", builderD='" + builderD + '\'' +
'}';
}
}
Builder
package com.kuang.builder;
//抽象的建造者:方法
public abstract class Builder {
abstract void builderA();//地基
abstract void builderB();//钢筋工程
abstract void builderC();//铺电线
abstract void builderD();//粉刷
//完工:得到产品
abstract Product getProduct();
}
Worker
package com.kuang.builder;
//具体的建造者:工人
public class Worker extends Builder {
private Product product;
public Worker() {
product = new Product();
}
@Override
void builderA() {
product.setBuilderA("地基");
System.out.println("地基");
}
@Override
void builderB() {
product.setBuilderB("钢筋工程");
System.out.println("钢筋工程");
}
@Override
void builderC() {
product.setBuilderC("铺电线");
System.out.println("铺电线");
}
@Override
void builderD() {
product.setBuilderD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
Director
package com.kuang.builder;
//指挥:核心,负责指挥构建一个工程,工程如何构建,由它决定
public class Director {
//指挥工人按照顺序建房子
public Product build(Builder builder){
builder.builderA();
builder.builderB();
builder.builderC();
builder.builderD();
return builder.getProduct();
}
}
Test
package com.kuang.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());
}
}
将一个复杂的构件与其表示相分离,使得同样的构件过程可以创建不同的表示
Builder
抽象建造者,给出一个抽象接口, 以规范产品对象的各个组成成分的建造. 这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建
ConcreteBuilder
实现Builder接口, 针对不同的商业逻辑, 具体化复杂对象的各部分的创建, 即具体建造者
Director
指挥者, 调用具体建造者来创建复杂对象的各个部分, 在指导者不涉及具体产品的信息, 只负责保证对象各部分完整创建或者按某种顺序创建
Product
要创建的复杂对象, 即产品角色
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZJYIXcNF-1615121940908)(C:\Users\MengFei\AppData\Roaming\Typora\typora-user-images\image-20210220152007964.png)]
Product
package com.kuang.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
package com.kuang.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 com.kuang.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 com.kuang.builder.demo02;
public class Test {
public static void main(String[] args) {
//服务员
Worker worker = new Worker();
//可以按默认走,也可以自由组合
Product product = worker.BuildA("全家桶").BuildB("雪碧").getProduct();
System.out.println(product.toString());
}
}
运行结果
Product{BuildA='全家桶', BuildB='雪碧', BuildC='薯条', BuildD='甜点'}
克隆
Prototype
Cloneable接口
clone()方法
Video
package com.kuang.prototype.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 com.kuang.prototype.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);
//v1克隆v2
//Video v2 = new Video( "狂神说Java", date);
Video v2 = (Video) v1.clone();
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
date.setTime(22131231);
System.out.println("++++++++++++++++++++++++++++++++++++++");
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
}
}
运行结果
v1=>Video{name='狂神说Java', createTime=Thu Dec 10 23:52:48 CST 2020}
v2=>Video{name='狂神说Java', createTime=Thu Dec 10 23:52:48 CST 2020}
++++++++++++++++++++++++++++++++++++++
v1=>Video{name='狂神说Java', createTime=Thu Jan 01 14:08:51 CST 1970}
v2=>Video{name='狂神说Java', createTime=Thu Jan 01 14:08:51 CST 1970}
Video
package com.kuang.prototype.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 com.kuang.prototype.demo02;
import java.util.Date;
/*
客户端:克隆
*/
public class Bilibili {
public static void main(String[] alrgs) throws CloneNotSupportedException {
//原型对象v1
Date date = new Date();
Video v1 = new Video("狂神说Java", date);
//v1克隆v2
//Video v2 = new Video( "狂神说Java", date);
Video v2 = (Video) v1.clone();
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
date.setTime(22131231);
System.out.println("+++++++++++++++++++++++++++++++++++");
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
}
}
运行结果
v1=>Video{name='狂神说Java', createTime=Thu Dec 10 23:56:38 CST 2020}
v2=>Video{name='狂神说Java', createTime=Thu Dec 10 23:56:38 CST 2020}
+++++++++++++++++++++++++++++++++++
v1=>Video{name='狂神说Java', createTime=Thu Jan 01 14:08:51 CST 1970}
v2=>Video{name='狂神说Java', createTime=Thu Dec 10 23:56:38 CST 2020}
结构性模式:
作用
从程序的结构上实现松耦合, 从而可以扩大整体的类结构,用来解决更大的问题
适配器模式就像USB网线转换器
Adaptee
package com.kuang.adapter;
//要被适配的类:网线
public class Adaptee {
public void request() {
System.out.println("连接网线上网");
}
}
Adapter
package com.kuang.adapter;
//真正的适配器,需要连接USB,连接网线~
public class Adapter extends Adaptee implements NetToUsb {
@Override
public void handleRequest() {
//上网的具体实现,找一个转接头
super.request();
}
}
NetToUsb
package com.kuang.adapter;
//按1口转换器的抽象实现~
public interface NetToUsb {
//作用:处理请求,网线=>usb
public void handleRequest();
}
Adapter2
package com.kuang.adapter;
//真正的适配器,需 要连接USB,连接网线~
public class Adapter2 implements NetToUsb {
//组合模式
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
//上网的具体实现,找一个转接头
adaptee.request();//可以上网
}
}
Computer
package com.kuang.adapter;
//客户端关: 想上:网,插不L:网线~
public class Computer {
//我们的电脑需要连接:转换器才可以:网
public void net(NetToUsb adapter) {
//.上网的具体实现, 找个转换器
adapter.handleRequest();
}
public static void main(String[] args) {
/* //电脑,适配器,网线~
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter adapter = new Adapter(); //转按器
computer.net(adapter);*/
System.out.println("++++++++++++++++++++++++++++++");
//电脑,适配器,网线~
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter2 adapter = new Adapter2(adaptee); //转换器
computer.net(adapter);
}
}
角色分析
桥接模式是将抽象部分与它的实现部分分离, 使他们都可以独立地变化, 它是一种对象结构型模式, 又称为柄体(Handle and Body)模式或接口(Interface)模式
分析:
这个场景中有两个变化的维度: 品牌, 类型
代码实现大脑所想
Brand
package com.kuang.bridge;
//品牌
public interface Brand {
void info();
}
Lenovo
package com.kuang.bridge;
//联想品牌
public class Lenovo implements Brand {
@Override
public void info() {
System.out.print("联想");
}
}
Apple
package com.kuang.bridge;
//联想品牌
public class Apple implements Brand {
@Override
public void info() {
System.out.print("苹果");
}
}
Computer
package com.kuang.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.print("台式机");
}
}
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.print("笔记本");
}
}
Test
package com.kuang.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();
}
}
运行结果
苹果笔记本
联想台式机
原理简单理解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBRI0isV-1615121940917)(C:\Users\MengFei\AppData\Roaming\Typora\typora-user-images\image-20210221181150666.png)]
是SpringAOP的底层 [SpringAOP和SpringMVC]
代理模式的分类
角色分析:
代码步骤:
接口
public interface Rent {
public void rent();
}
真实角色
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子");
}
}
代理角色
//代理
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("签合同");
}
}
客户端访问代理角色
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
//代理,中介帮房东租房子,但是 代理一般会有一些附属操作
Proxy proxy = new Proxy(host);
//不用面对房东,直接找中介租房即可
proxy.rent();
}
代理模式的好处:
缺点:
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
聊聊AOP:纵向开发,横向开发。
创建一个抽象角色
//抽象角色:增删改查业务
public interface UserService {
void add();
void delete();
void update();
void query();
}
我们需要一个真实对象来完成这些增删改查操作
//真实对象,完成增删改查操作的人
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("查询了一个用户");
}
}
需求来了,现在我们需要增加一个日志功能,怎么实现!
设置一个代理类来处理日志, 代理角色
//代理角色,在这里面增加日志的实现
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+"方法");
}
}
测试访问类:
public class Client {
public static void main(String[] args) {
//真实业务
UserServiceImpl userService = new UserServiceImpl();
//代理类
UserServiceProxy proxy = new UserServiceProxy();
//使用代理类实现日志功能!
proxy.setUserService(userService);
proxy.add();
}
}
需要了解的两个类: Proxy: 代理, InvocationHandler: 调用处理程序
InvocationHandler(调用处理程序)
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
代码实现
抽象角色和真实角色和之前的一样!
Rent . java 即抽象角色
//抽象角色:租房
public interface Rent {
public void rent();
}
Host . java 即真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
ProxyInvocationHandler. java 即代理角色
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) throwsThrowable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client . java
//租客
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. java 即代理角色
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) throwsThrowable {
log(method.getName());
//动态代理的本质,就是使用反射机制实现
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
测试
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();
}
}
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!