OOP七大原则
开闭原则:对扩展开发,对修改关闭。
里氏替换原则: 继承必须确保超类所拥有的性质在子类中仍然成立
依赖倒置原则: 要面向接口编程,不要面向实现编程。
单一职责原则: 控制类的粒度大小、将对象解耦、提高其内聚性。
接口隔离原则: 要为各个类建立它们需要的专用接口
迪米特法则: 只与你的直接朋友交谈,不跟"陌生人”说话。
合成复用原则: 尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
单例模式
饿汉式
package com.sanjin.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 HUBGRY= new Hungry();
public static Hungry getInstance(){
return HUBGRY;
}
}
DCL懒汉式
package com.sanjin.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
//懒汉式单例
public class LazyMan {
private static boolean sanjin =false;
private LazyMan(){
synchronized (LazyMan.class){
if (sanjin==false){
sanjin=true;
}else {
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName());
}
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
*/
}
}
}
if (lazyMan==null){
lazyMan=new LazyMan();
}
return lazyMan;
}
//单线程下ok
//多线程并发
//反射!
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//LazyMan instance = LazyMan.getInstance();
Field sanjin = LazyMan.class.getDeclaredField("sanjin");
sanjin.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
LazyMan lazyMan = declaredConstructor.newInstance();
sanjin.set(lazyMan,false);
LazyMan lazyMan1 = declaredConstructor.newInstance();
System.out.println(lazyMan==lazyMan1);
}
}
静态内部类
package com.sanjin.single;
//静态内部类
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.sanjin.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//enum 是一个什么? 本身也是一个class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle enumSingle = declaredConstructor.newInstance();
System.out.println(instance==enumSingle);
}
}
枚举类型的最终反编译
// 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.sanjin.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/sanjin/single/EnumSingle, name);
}
private EnumSingle(String s, int i)
{
super(s, i);
}
public EnumSingle getInstance()
{
return INSTANCE;
}
public static final EnumSingle INSTANCE;
private static final EnumSingle $VALUES[];
static
{
INSTANCE = new EnumSingle("INSTANCE", 0);
$VALUES = (new EnumSingle[] {
INSTANCE
});
}
}
简单(静态)工厂模式
满足 :开闭原则,依赖倒置原则,迪米特法则。
核心本质:
实例化对象不使用new,用工厂方法代替。
将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
简单工厂模式:
创建接口:
package model.factory.simple;
public interface Car {
void name();
}
两个实现类
package model.factory.simple;
public class Tesla implements Car{
@Override
public void name() {
System.out.println("Tesla");
}
}
package model.factory.simple;
public class WuLing implements Car{
@Override
public void name() {
System.out.println("五菱神车");
}
}
创建工厂
package model.factory.simple;
// 静态工厂模式
// 增加新的产品,必须修改代码,这是弊端,这违背了开闭原则
public class CarFactory {
public static Car getCar(String car){
if (car==null||car.length()<=0){
return null;
}
if (car.equals("五菱")){
return new WuLing();
}else if (car.equals("Tesla")){
return new Tesla();
}
return null;
}
}
调用实现
package model.factory.simple;
public class Consumer {
public static void main(String[] args) {
// 1. 了解这个接口和实现类才能new出来
// Car car1=new WuLing();
// Car car2=new Tesla();
// car1.name();
// car2.name();
//2. 使用工厂创建
Car car = CarFactory.getCar("五菱");
Car tesla = CarFactory.getCar("Tesla");
car.name();
tesla.name();
}
}
简单工厂模式简单易懂,但是如果要增加产品,就要修改源代码,破坏开闭规则。
工厂方法模式
在简单工厂模式的前提下,我们增加以下类
工厂方法模式类
package model.factory.method;
//工厂方法模式
public interface CarFactory {
Car getCar();
}
实现工厂方法
package model.factory.method;
public class TeslaFactory implements CarFactory{
@Override
public Car getCar() {
return new Tesla();
}
}
package model.factory.method;
public class WuLingFactory implements CarFactory{
@Override
public Car getCar() {
return new WuLing();
}
}
测试
package model.factory.method;
public class Consumer {
public static void main(String[] args) {
Car car = new WuLingFactory().getCar();
Car car1 = new TeslaFactory().getCar();
car.name();
car1.name();
}
}
此时如果想再新增一个产品,只需实现工厂方法
package model.factory.method;
public class Mobai implements Car{
@Override
public void name() {
System.out.println("摩拜单车");
}
}
package model.factory.method;
public class MobaiFactory implements CarFactory{
@Override
public Car getCar() {
return new Mobai();
}
}
由此发现,这样可以不破坏最初代码,但是繁琐了很多。
抽象工厂模式
抽象工厂模式简单来说就是工厂的工厂,具体的话,我们先看个例子
首先我们先写一个手机的接口
package model.factory.abstract1;
//手机产品接口
public interface PhoneProduct {
void start();
void shutdown();
void callup();
void sendSMS();
}
我们在来写一个路由器的接口
package model.factory.abstract1;
//路由器产品接口
public interface RouterProduct {
void start();
void shutdown();
void openWifi();
void setting();
}
现在有华为和小米两个产品
package model.factory.abstract1;
public class HuaWeiPhone implements PhoneProduct{
@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("华为发短信");
}
}
package model.factory.abstract1;
public class HuaWeiRouter implements RouterProduct{
@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 model.factory.abstract1;
public class XiaomiPhone implements PhoneProduct{
@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("小米发短信");
}
}
package model.factory.abstract1;
//小米路由器
public class XiaomiRouter implements RouterProduct{
@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 model.factory.abstract1;
//抽象产品工厂
public interface ProductFactory {
//生产手机
PhoneProduct phoneProduct();
//生产路由器
RouterProduct routerProduct();
}
有了抽象工厂,我们还不能指定到底是生产华为的手机还是小米的路由器,所以
package model.factory.abstract1;
public class HuaWeiFactory implements ProductFactory{
@Override
public PhoneProduct phoneProduct() {
return new HuaWeiPhone();
}
@Override
public RouterProduct routerProduct() {
return new HuaWeiRouter();
}
}
package model.factory.abstract1;
public class XIaomiFactory implements ProductFactory{
@Override
public PhoneProduct phoneProduct() {
return new XiaomiPhone();
}
@Override
public RouterProduct routerProduct() {
return new XiaomiRouter();
}
}
增加测试类:
package model.factory.abstract1;
public class Client{
public static void main(String[] args) {
System.out.println("===========小米");
//小米工厂
XIaomiFactory xIaomiFactory = new XIaomiFactory();
PhoneProduct phoneProduct = xIaomiFactory.phoneProduct();
phoneProduct.callup();
phoneProduct.sendSMS();
RouterProduct routerProduct = xIaomiFactory.routerProduct();
routerProduct.openWifi();
System.out.println("============华为");
HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
PhoneProduct phoneProduct1 = huaWeiFactory.phoneProduct();
phoneProduct1.callup();
RouterProduct routerProduct1 = huaWeiFactory.routerProduct();
routerProduct1.openWifi();
}
}
最后的关系如下:
调理一遍:
用户选择工厂,工厂实现了抽象工厂的内容,然后用户根据需求调用所需要的产品。
建造者模式
由上面的工厂模式,我们可以理解为创建了一个族的产品,然建造者就是把这些东西组装起来变成一个类。
比如,造房子的过程。
我们先要有地基,然后钢筋工厂,然后铺电线,粉刷。最后形成一个房子。
建造者,模式,就是抽象成一个指挥者,你去控制工人们怎么做。蓝图在你这里,你只管决定然后做出最后的产品。
如下:
package model.builder.demo1;
//抽象的建造者 : 定义 方法
public abstract class Builder {
abstract void buildA();//地基
abstract void buildB();//钢筋工厂
abstract void buildC();//电线
abstract void buildD();//粉刷
//得到产品
abstract Product getProduct();
}
package model.builder.demo1;
//具体的建造者: 工人
public class Worker extends Builder{
private Product product;
public Worker() {
this.product = new Product();
}
@Override
void buildA() {
product.setBulidA("地基");
System.out.println("地基");
}
@Override
void buildB() {
product.setBulidB("钢筋工程");
System.out.println("钢筋");
}
@Override
void buildC() {
product.setBulidC("电线");
System.out.println("电线");
}
@Override
void buildD() {
product.setBulidD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
package model.builder.demo1;
//产品 : 房子
public class Product {
private String bulidA;
private String bulidB;
private String bulidC;
private String bulidD;
public String getBulidA() {
return bulidA;
}
public void setBulidA(String bulidA) {
this.bulidA = bulidA;
}
public String getBulidB() {
return bulidB;
}
public void setBulidB(String bulidB) {
this.bulidB = bulidB;
}
public String getBulidC() {
return bulidC;
}
public void setBulidC(String bulidC) {
this.bulidC = bulidC;
}
public String getBulidD() {
return bulidD;
}
public void setBulidD(String bulidD) {
this.bulidD = bulidD;
}
@Override
public String toString() {
return "Product{" +
"bulidA='" + bulidA + '\'' +
", bulidB='" + bulidB + '\'' +
", bulidC='" + bulidC + '\'' +
", bulidD='" + bulidD + '\'' +
'}';
}
}
package model.builder.demo1;
//指挥:核心 如何构建由他决定
public class Director {
//指挥工人按照顺序造房子
public Product build(Builder builder){
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
package model.builder.demo1;
public class Test {
public static void main(String[] args) {
//指挥
Director director=new Director();
//指挥具体的工人完成产品
Product build = director.build(new Worker());
System.out.println(build.toString());
}
}
但是这样,只是定死的内容,我们大多数场景,是由用户为指挥者。
我们举例为麦当劳,里面有套餐还可以用户自定义 就是单点。
初始值就为套餐
package model.builder.demo2;
//建造者
public abstract class Bulider {
public abstract Bulider buliderA(String msg);//汉堡
public abstract Bulider buliderB(String msg);//可乐
public abstract Bulider buliderC(String msg);//薯条
public abstract Bulider buliderD(String msg);//甜点
abstract Product getProduct();
}
package model.builder.demo2;
//产品、套餐
public class Product {
private String BuildA="汉堡";
private String BuildB="可乐";
private String BuildC="薯条";
private String BuildD="甜点";
public void setBuildA(String buildA) {
BuildA = buildA;
}
public void setBuildB(String buildB) {
BuildB = buildB;
}
public void setBuildC(String buildC) {
BuildC = buildC;
}
public void setBuildD(String buildD) {
BuildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"BuildA='" + BuildA + '\'' +
", BuildB='" + BuildB + '\'' +
", BuildC='" + BuildC + '\'' +
", BuildD='" + BuildD + '\'' +
'}';
}
}
package model.builder.demo2;
//具体建造者
public class Worker extends Bulider{
private Product product;
public Worker() {
this.product = new Product();
}
@Override
public Bulider buliderA(String msg) {
product.setBuildA(msg);
return this;
}
@Override
public Bulider buliderB(String msg) {
product.setBuildB(msg);
return this;
}
@Override
public Bulider buliderC(String msg) {
product.setBuildC(msg);
return this;
}
@Override
public Bulider buliderD(String msg) {
product.setBuildD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
package model.builder.demo2;
public class Test {
public static void main(String[] args) {
//服务员
Worker worker=new Worker();
Product product = worker.buliderA("全家桶")
.getProduct();
System.out.println(product.toString());
}
}
这样我们就可以自定义建造什么了。
原型模式
原型模式就是当我们new出来一个对象,如果想克隆这个对象,不用new 而是把这个对象当作一个原型所引用。
我们举个例子,视频搬运。
package model.prototype.demo1;
import java.util.Date;
/*
1. 实现一个接口 Cloneable
2. 重写一个方法 clone()
*/
//Video
public class Video implements Cloneable {//搬运,克隆别人的视频
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
public Video() {
}
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 +
'}';
}
}
package model.prototype.demo1;
import java.util.Date;
/*
客户端: 克隆
*/
public class Bilibili {
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象
Date date = new Date();
Video v1 = new Video("三金", date);
System.out.println(v1);
System.out.println("hash="+v1.hashCode());
//v1可以克隆v2
Video v2 = (Video) v1.clone();//克隆出来的对象和原来一样
System.out.println(v2);
System.out.println("hash="+v2.hashCode());
v2.setName("克隆三金");
System.out.println(v2);
}
}
结果是
Video{name='三金', createTime=Wed Apr 21 19:04:56 GMT+08:00 2021}
hash=1735600054
Video{name='三金', createTime=Wed Apr 21 19:04:56 GMT+08:00 2021}
hash=21685669
Video{name='克隆三金', createTime=Wed Apr 21 19:04:56 GMT+08:00 2021}
但是如果我们改变的了date的值,发现v1 v2都会改变。这就是浅克隆。
基本类型值会相互克隆,引用类型会指向相同的地址。
一般我们都希望互不干扰,就是深克隆。
所以我们重写clone方法。
@Override
protected Object clone() throws CloneNotSupportedException {
Object clone =super.clone();
Video v= (Video) clone;
v.createTime= (Date) this.createTime.clone();
return clone;
}
Video{name='三金', createTime=Thu Jan 01 12:12:31 GMT+08:00 1970}
Video{name='克隆三金', createTime=Wed Apr 21 19:12:32 GMT+08:00 2021}
这样就可以变成一对一的了
适配器模式
适配器模式我们可以想象成电脑网线转换器
适配器就是让两个东西相互兼容,相互影响。
举例如下:
网线-适配器-usb
网线:
package model.adapter;
//要被适配的类 : 网线
public class Adaptee {
public void request(){
System.out.println("连接网线上网。");
}
}
适配器:
package model.adapter;
//真正的适配器 需要连接usb 网线
public class Adapter extends Adaptee implements NetToUSB{
@Override
public void handleRequest() {
super.request();//可以上网了
}
}
usb:
package model.adapter;
//接口转换器的抽象实现
public interface NetToUSB {
//处理请求 把网线插到usb
public void handleRequest();
}
测试:
package model.adapter;
//客户端类 : 想上网,插不上网线
public class Computer {
//我们电脑需要连接到转接器才能上网
public void net(NetToUSB adapter){
//上网的具体实现 找一个转接头
adapter.handleRequest();
}
public static void main(String[] args) {
//电脑 适配器 网线
Computer computer = new Computer();//电脑
Adapter adapter = new Adapter();//转接器
Adaptee adaptee = new Adaptee();//网线
computer.net(adapter);
}
}
这样就简单的实现了适配器模式的基本用途。
但是我们不想只要这一根网线进这一个适配器(因为用了继承)
所以对适配器进行改进
package model.adapter;
//组合
//对象适配器
public class Adapter2 implements NetToUSB{
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
adaptee.request();
}
}
这样每次调用的时候可以指定网线了。
package model.adapter;
//客户端类 : 想上网,插不上网线
public class Computer {
//我们电脑需要连接到转接器才能上网
public void net(NetToUSB adapter){
//上网的具体实现 找一个转接头
adapter.handleRequest();
}
public static void main(String[] args) {
//电脑 适配器 网线
Computer computer = new Computer();//电脑
Adaptee adaptee = new Adaptee();//网线
Adapter2 adapter2 = new Adapter2(adaptee);//转接线2
computer.net(adapter2);
}
}
要体会这里的思想。
桥接模式
我们看下面的图
如果想获得苹果笔记本电脑 或者 联想台式电脑 该如何呢。
我们应该在这两个直接搭一个桥梁(可能有点像适配器模式,不过是不一样的,我们需要仔细考虑考虑)
我们根据上述建立代码
package model.bridge;
public interface Brand {
void info();
}
package model.bridge;
//苹果品牌
public class Apple implements Brand{
@Override
public void info() {
System.out.println("苹果");
}
}
package model.bridge;
//联想品牌
public class Lenovo implements Brand{
@Override
public void info() {
System.out.println("联想");
}
}
一个分支结束。
package model.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("笔记本");
}
}
这里我们使用了组合 ,通过构造器让两个分支有了联系。
这里如果体会不到好处的话 ,我再画一个图
这样就会变成多继承的关系。
所以就体现出了桥接的好处。
代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 Spring MVC】面试必问
代理模式的分类:
- 静态代理
- 动态代理
静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
代码步骤:
- 接口
package com.sanjin.demo01;
//租房
public interface Rent {
public void rent();
}
- 真实角色
package com.sanjin.demo01;
//房东
public class Host implements Rent{
public void rent() {
System.out.println("房东要出租房子");
}
}
- 代理角色
package com.sanjin.demo01;
public class Proxy implements Rent{
private Host host;
public Proxy(Host host) {
this.host = host;
}
public Proxy() {
}
public void rent() {
host.rent();
seeHouse();
fee();
contract();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//收中介费
public void fee(){
System.out.println("收中介费");
}
//合同
public void contract(){
System.out.println("签租赁合同");
}
}
- 客户端访问代理角色
package com.sanjin.demo01;
public class Client {
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
//代理,中介帮房东租房子,代理角色一般会有附属操作
Proxy proxy = new Proxy(host);
//你不用面对房东,直接找中介
proxy.rent();
}
}
代理模式的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共业务
- 公共业务就交给代理角色,实现了业务的分工
- 公共业务发生拓展的时候,方便集中管理!
缺点:
- 一个真实角色,就会又一个代理角色,代码量会翻倍,开发效率会变低
加深理解
- 接口
package com.sanjin.demo02;
public interface UserService {
void add();
void delete();
void apdate();
void query();
}
- 真实角色
package com.sanjin.demo02;
//真实对象
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void apdate() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查找了一个用户");
}
}
- 代理角色
package com.sanjin.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("del");
userService.delete();
}
public void apdate() {
log("upd");
userService.apdate();
}
public void query() {
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}
- 客户端
package com.sanjin.demo02;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
userServiceProxy.add();
}
}
动态代理
- 动态代理和静态代理角色一样
- 动态代理的类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理;基于类的动态代理
- 基于接口— JDK 动态代理【我们再这里使用】
- 基于类:cglib
- java字节码实现:javassist
需要了解两个类:Proxy: 代理, InvocationHandler:调用处理程序
InvocationHandler
动态代理类
package com.sanjin.domo04;
import com.sanjin.demo03.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//我们会用这个类 自动生成代理类
public class Proxy2 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);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质就是使用反射
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String mes){
System.out.println("执行了"+mes+"日志方法");
}
}
测试类
package com.sanjin.domo04;
import com.sanjin.demo02.UserService;
import com.sanjin.demo02.UserServiceImpl;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色
Proxy2 proxy2 = new Proxy2();
proxy2.setTarget(userService);//设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) proxy2.getProxy();
proxy.add();
proxy.delete();
}
}
动态代理的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共业务
- 公共业务就交给代理角色,实现了业务的分工
- 公共业务发生拓展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可