设计模式专题(2)----工厂模式与代理模式(重要)

第一节 简单工厂模式
  • 不是23种设计模式的一种
  • 工厂模式分为简单工厂模式,工厂方法,抽象工厂模式
  • 工厂模式的好处:

工厂模式是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。
利用工厂模式可以降低程序的耦合性,为后期的维护提供了很大的便利。
将选择实现类,创建对象同意管理和控制。从而将调用者跟我们的实现类解耦。

  • 工厂与容器的概念:

容器存储的是一个大块的东西,工厂是用来生产的。
工厂主要用来生产对象,代替new。容器是用来存储对象的。

  • 简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品的参数即可。但是工厂的职责过重,而且类型过多的时候不利于系统的扩展维护。
    在这里插入图片描述
  • 简单工厂的职责比较重,当类型过多的时候不利于系统的扩展维护。

简单代码示例:

package com.xiyou.shejimoshi.gongchangmoshi;

/**
 * 简单工厂模式
 */
public class JianDanFactory {
    public static void main(String[] args) {
        Car aodi = CarFactory.createCar("奥迪");
        Car jili = CarFactory.createCar("吉利");
        aodi.run();
        jili.run();
    }
}

/**
 * 汽车的抽象类
 */
interface Car{
    public void run();
}

/**
 * 奥迪汽车
 */
class AoDi implements Car{

    public void run() {
        System.out.println("奥迪车跑起来....");
    }
}


/**
 * 吉利汽车
 */
class JiLi implements Car{

    public void run() {
        System.out.println("吉利汽车跑起来....");
    }
}

/**
 * 汽车工厂
 */
class CarFactory{

    /**
     * 根据传进来的汽车名字,返回不同的汽车对象
     * @param name
     * @return
     */
    public static Car createCar(String name){
        if ("奥迪".equals(name)) {
            return new AoDi();
        }
        if ("吉利".equals(name)) {
            return new JiLi();
        }
        return null;
    }
}


第二节 单例设计模式的总结
  • 不推荐用双重检验锁的方式来创建单例(即使加上volatile禁止重排序也不推荐使用)
  • 如何选择单例创建的方式?

如果不需要延迟加载单例,可以使用枚举或者饿汉式,相对来说枚举更好。
如果需要延迟加载,可以使用静态内部类或者懒汉式,相对来说静态内部类更好。

  • 在开发当中饿汉式用的多。
  • 不要定义过多的常量,会造成内存溢出。
第三节 工厂方法设计模式

在这里插入图片描述
工厂方法模式,又称作多态性工厂模式,在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而具体创建的工作交给子类去做,该核心类称为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不用去管哪个产品类应当被实例化。

  • 代码介绍:
package com.xiyou.shejimoshi.gongchangfangfa;

public class GongChangFangFa {
    public static void main(String[] args) {
        Car aodi = new AodiFactory().createCar();
        Car jili = new JiLiFactory().createCar();
        aodi.run();
        jili.run();
    }
}

/**
 * 汽车的接口
 */
interface Car{
    public void run();
}

/**
 * 奥迪汽车
 */
class AoDi implements Car{

    public void run() {
        System.out.println("我是奥迪汽车");
    }
}

/**
 * 吉利汽车
 */
class JiLi implements Car{

    public void run() {
        System.out.println("我是吉利汽车");
    }
}

/**
 * 汽车工厂,生产汽车
 */
interface CarFactory{
    public Car createCar();
}

/**
 * 吉利汽车工厂
 */
class JiLiFactory implements CarFactory{
    public Car createCar() {
        return new JiLi();
    }
}

/**
 * 奥迪汽车工厂
 */
class AodiFactory implements CarFactory{

    public Car createCar() {
        return new AoDi();
    }
}
第四节 抽象工厂模式
  • 抽象工厂简单的说就是工厂的工厂,抽象工厂可以创建具体的工厂,由具体工厂来产生具体产品。
    在这里插入图片描述
    在这里插入图片描述
  • 可以理解为工厂的工厂,不是一个产品簇下面的,又生产汽车(包括汽车A,B,C)又卖苹果(包括苹果A,B,C)。
  • 代码如下:
package com.xiyou.mayi.thread5.chouxianggongchang;

/**
 * 抽象工厂
 */
public class ChouXaingFactory {
    public static void main(String[] args) {
        CarFactory jiLi = new JiLi();
        CarFactory aoDi = new AoDi();
        jiLi.createChair().run();
        jiLi.createEngine().run();
        aoDi.createEngine().run();
        aoDi.createChair().run();
    }
}

/**
 * 发动机的抽象
 */
interface Engine{
    void run();

    void start();
}

/**
 * 发动机A
 */
class EngineA implements Engine{

    @Override
    public void run() {
        System.out.println("发动机A的run");
    }

    @Override
    public void start() {
        System.out.println("发动机A的start");
    }
}

class EngineB implements Engine{

    @Override
    public void run() {
        System.out.println("发动机B的run");
    }

    @Override
    public void start() {
        System.out.println("发动机B的start");
    }
}

/**
 * 座椅的抽象类
 */
interface Chair{
    void run();
}

/**
 * 座椅A
 */
class ChairA implements Chair{

    @Override
    public void run() {
        System.out.println("chairA的run");
    }
}

/**
 * 座椅B
 */
class ChairB implements Chair{

    @Override
    public void run() {
        System.out.println("chairB的run");
    }
}

/**
 * 汽车工厂
 */
interface CarFactory{
    // 创建发动机
    Engine createEngine();

    // 创建座椅
    Chair createChair();
}

/**
 * 吉利汽车
 */
class JiLi implements CarFactory{

    @Override
    public Engine createEngine() {
        return new EngineA();
    }

    @Override
    public Chair createChair() {
        return new ChairA();
    }
}

/**
 * 奥迪
 */
class AoDi implements CarFactory{

    @Override
    public Engine createEngine() {
        return new EngineB();
    }

    @Override
    public Chair createChair() {
        return new ChairB();
    }
}
第五节 代理模式概述
  • 通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或者调用后处理,即AOP。AOP的核心技术就是面向切面编程。
    在这里插入图片描述

  • 代理模式应用的场景:
    SpringAop,事务原理,日志打印,权限控制,远程调用,安全代理

  • 代理的分类:
    (1)静态代理(静态定义代理类)
    (2)动态代理(动态生成代理类)
    (3)JDK自带动态代理(必须要有接口)
    (4)CGLIB,Javaassist(字节码操作库)

  • 静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行之前就确定了。
不推荐使用,冗余度高,不适合扩展

  • 举例说明:
/**
 * JDK的静态代理
 * 实现了业务的接口类,自己重写该方法,进行覆盖加前后操作
 */
public class JingTaiProxy implements IUserDao{
    // 真实的实现类的对象
    private IUserDao target;

    JingTaiProxy(IUserDao userDao){
        target = userDao;
    }

    /**
     * 自己重写的方法,对其进行覆盖,加自己的逻辑
     */
    public void save() {
        System.out.println("执行save之前执行的方法...");
        target.save();
        System.out.println("执行save之后执行的方法...");
    }
}

/**
 * 接口类
 */
interface IUserDao{
    void save();
}

/**
 * 具体的实现类
 */
class UserDao implements IUserDao{

    public void save() {
        System.out.println("已经保存了数据...");
    }
}

第六节 jdk的动态代理
  • 动态代理

代理对象,不需要实现接口
代理对象的生成是利用了JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/ 目标对象实现的接口的类型)
动态代理也叫做JDK代理,接口代理

  • JDK动态代理通过反射拿到代理对象,CGLIB动态代理通过ASM开源包,对代理对象类的class文件加载出来,通过修改字节码生子类来处理。
  • jdk动态代理的原理:

是根据类加载器和接口创建代理类,该代理类是接口的实现类,所以必须使用接口,面向接口生成代理(jdk必须要接口的原因)

  • 实现方式:
  1. 通过实现InvocationHandler接口创建自己的调用处理器DongTaiProxy handler = new DongTaiProxy (…)
  2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader, new Class[]{…})
  3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class})
  4. 通过构造函数创建代理对象,此时需要将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
  • jdk动态代理的缺点是必须面向接口,目标业务类必须实现接口,因为我们创建的代理类实际上就是该接口的实现类,覆盖了其方法。
  • 举例说明:
package com.xiyou.shejimoshi.dailimoshi.jdkProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK的动态代理
 */
public class DongTaiProxy implements InvocationHandler {

    // 业务实现类的对象,用来调用具体的业务方法
    private Object target;

    // 通过构造函数传入目标对象
    public DongTaiProxy(Object target){
        this.target = target;
    }

    /**
     * 我们虽然会调用业务方法,但是实际上调用了该方法
     * 代理实际上不就是利用了多台的思想,调用的实际上是覆盖的方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("调用开始处理。。。");
        // 调用方法,反射调用target是实际的业务方法,args是参数
        result = method.invoke(target, args);
        System.out.println("调用结束。。。");
        return result;
    }

    public static void main(String[] args) {
        // 声明实际的对象
        IUserDao userDao = new UserDao();
        DongTaiProxy dongTaiProxy = new DongTaiProxy(userDao);
        // 获取实际对象的类加载器
        ClassLoader classLoader = userDao.getClass().getClassLoader();
        // 得到实际对象的接口
        Class<?>[] interfaces = userDao.getClass().getInterfaces();
        // 生成代理对象,该代理对象不是我们生成的,是由jdk自动为我们生成的
        IUserDao iUserDao = (IUserDao) Proxy.newProxyInstance(classLoader, interfaces, dongTaiProxy);
        // 这时候虽然我们看着是在调用save方法,实际上我们调用的是代理中的invoke方法。
        iUserDao.save();
    }
}


第七节 cglib动态代理设计模式
  • JDK使用的是反射的技术,而CGLIB使用的是asm字节码生成框架生产代理类的字节码文件。
  • CGLIB并不需要委托类实现接口。而JDK的动态代理必须实现接口。所以CGLIB是针对类的,JDK是针对接口的。
  • CGLIB是针对类实现的代理。主要是对指定的类生成一个子类,覆盖其中的方法(这样子才可以对指定类进行扩展性功能,在方法之前或者之后进行相关的处理)。因为是自动生成一个子类,所以该类或者方法不能生成为final,因为无法继承。
  • 举例说明:
package com.xiyou.shejimoshi.dailimoshi.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * CGLIB的动态代理
 */
public class CglibProxy implements MethodInterceptor {
    // 真实的对象,即被代理的对象
    private Object targetObject;

    /**
     * 该方法的作用是生成代理对象
     * 原理:
     * 由CGLIB默认生成被代理对象的一个子类,回调返回该对象,创建子类对象
     * @param targetObject
     * @return
     */
    public Object getInstance(Object targetObject){
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        // 设置其父类是被代理对象的类
        enhancer.setSuperclass(targetObject.getClass());
        // 回调设置成当前对象为代理对象
        enhancer.setCallback(this);
        return enhancer.create();
    }

    /**
     * 代理方法
     * @param o
     * @param method 具体的方法
     * @param objects 参数
     * @param methodProxy 代理对象
     * @return
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行之前的方法...");
        Object result = methodProxy.invoke(targetObject, objects);
        System.out.println("执行之后的方法...");
        return result;
    }


    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        UserDao userDao = (UserDao)cglibProxy.getInstance(new UserDao());
        userDao.save();
    }
}


/**
 * 接口类
 */
interface IUserDao{
    void save();
}

/**
 * 具体的实现类
 */
class UserDao implements IUserDao{

    public void save() {
        System.out.println("已经保存了数据...");
    }
}
补充:

CHLIB动态代理和JDK动态代理的区别:

  1. java动态代理是利用了反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理;而CGLIB动态代理运用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类进行处理。
  2. JDK动态代理只能对实现了接口的类生成代理,而不能针对类,只能针对接口。而CGLIB针对类实现的代理,主要是对指定的类生成一个子类,覆盖其方法。
  3. 注意:因为核心就是集成,用子类的方法覆盖父类的方法,所以该类或者方法,不要声明final,final修饰的类无法集成,方法无法重写
  • 在Spring中:
    (1)如果目标对象实现了接口,默认会用JDK的动态代理实现AOP
    (2)如果目标对象使用了接口,可以强制使用CGLIB实现AOP
    (3)如果目标对象没有实现接口,必须采用CGLIB库,spring会自动在JDK和CGLIB之间转换。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值