单例&工厂&代理模式总结

版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.csdn.net/sun8112133/article/details/80058200

  本篇主要对Spring框架中所涉及到的常见几种设计模式做简要总结(单例模式、工厂方法模式、抽象工厂模式、代理模式),其他不做过多的详细介绍。。

  设计模式的原则:不改代码,只添代码。

Spring框架所涉及到的常见设计模式(三种创建型及一种结构型):

  一、单例模式(创建型)
  二、工厂方法模式(创建型)
  三、抽象工厂模式(创建型)
  四、代理模式(结构型)





一、单例模式(创建型)

1、什么是单例模式

  单例对象在程序中有且只有一个实例。

2、单例模式的好处
  1)节约内存,频繁创建对象,对系统内存也是一笔很大的开销;
  2)省去 new操作符,降低了系统内存的使用频率,减轻GC压力;
  3)对于比如像交易核心类,控制着整个交易流程,如果创建多个话,会使系统完全乱套。
3、单例模式的简单写法
  1)懒汉模式:
public class Singleton {
    private Singleton instance;
    private Singleton() { }
    public Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  2)饿汉模式:
public class Singleton {
    private Singleton instance = new Singleton();
    private Singleton() { }
    public Singleton getInstance() {
        return instance;
    }
}


二、工厂方法模式

1、什么是工厂方法模式

  建立一个工厂类,对实现了同一接口的产品类进行实例的创建。

2、工厂方法模式的好处
  1)统一new对象,不在外面new对象,而在工厂(类)中new对象;
  2)方便安全,将对象的创建与使用分开,隐藏了创建过程的复杂度。
3、工厂方法模式的缺点

  类的创建依赖工厂类,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,工厂方法模式不利用扩展。

4、工厂方法模式的写法
  1)简单工厂模式:
// 发送接口
public interface Sender {
    public void send();
}
// 邮箱
public class Mail implements Sender {
    @Override
    public void send() {
        System.out.println("发送邮件!");
    }
}
// 短信
public class Sms implements Sender {
    @Override
    public void send() {
        System.out.println("发送短信!");
    }
}
// 创建具有发送功能的产品工厂类
public class SendFactory {
    public Sender getSender(String type) {
        if ("mail".equals(type)) {
            return new Mail();
        } else if ("sms".equals(type)) {
            return new Sms();
        } else {
            System.err.println("请输入正确的类型");
            return null;
        }
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        SendFactory factory = new SendFactory();
        Sender mail = factory.getSender("mail");
        mail.send();   // 输出:发送邮件!
    }
}
  2)静态工厂模式(对工厂进行了改变):
// 创建具有发送功能的产品工厂类
public class SendFactory {
    // 获取 邮箱 对象
    public static Sender getMail() {
        return new Mail();
    }
    // 获取 短信 对象
    public static Sender getSms() {
        return new Sms();
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        Sender mail = SendFactory.getMail();
        mail.send();   // 输出:发送邮件!
    }
}


三、抽象工厂模式

1、什么是抽象工厂模式

  创建多个工厂类,一旦需要增加新的功能,直接增加新的工厂类就可以了。

2、抽象工厂模式的好处

  如果你现在想增加一个功能,则只需做一个实现类实现XXX接口,同时做一个工厂类,实现工厂XXX接口,就OK了,无需去改动现成的代码。这样做,相比起工厂方法模式更利于扩展。

3、抽象工厂模式的写法
// 发送接口
public interface Sender {
    public void send();
}
// 邮箱
public class Mail implements Sender {
    @Override
    public void send() {
        System.out.println("发送邮件!");
    }
}
// 短信
public class Sms implements Sender {
    @Override
    public void send() {
        System.out.println("发送短信!");
    }
}
// 新增加一个QQ
public class QQ implements Sender {
    @Override
    public void send() {
        System.out.println("发送QQ消息!");
    }
}

// 创建一个专门用来生产“产品”的工厂类接口
public interface SenderFactory {
    public static Sender getSender();
}
// 创建一个专门用来生产“邮箱产品”的工厂类
public class MailFactory implements SenderFactory {
    @Override
    public static Sender getSender() {
        return new Mail();
    }
}
// 创建一个专门用来生产“短信产品”的工厂类
public class SmsFactory implements SenderFactory {
    @Override
    public static Sender getSender() {
        return new Sms();
    }
}
// 新增加一个专门用来生产“QQ产生”的工厂类
public class QQFactory implements SenderFactory {
    @Override
    public static Sender getSender() {
        return new QQ();
    }
}

// 测试类
public class Test {
    public static void main(String[] args) {
        Sender QQ = QQFactory.getSender();
        QQ.send();   // 输出:发送QQ消息!
    }
}


四、代理模式

1、什么是代理模式

  代理模式就是代替原对象进行一系列的操作,比如我们去火车站买票,火车站代售处就可以代替火车站进行售票,但需要在原车票的费用上额外加一些手续费(以下是去火车站买票和去代售处买票的序列图)。

  • 创建目标对象的类叫目标类或者被代理类(火车站);
  • 创建代理对象的类加代理类(代售处)。
Created with Raphaël 2.1.0 火车站 火车站 火车票 火车票 去火车站 从家走需要2个小时才可以到达火车站,太不方便了!! 买票 需要支持20元
Created with Raphaël 2.1.0 代售处 代售处 火车票 火车票 去代售处 从家走10分钟就可以到达代售处! 买票 需要支持25元(5元手续费)
2、代理模式的好处

  从以上序列图我们就可以看到代售处比火车站更加快捷方便,只需要交5元钱就可以节省大量的时间买到票。我们可以为“目标对象”提供一种“代理对象”以便于控制对目标对象的访问,也就是在“目标对象”的基础上添加一些功能。

3、代理模式的写法
  1)静态代理模式:
// 买火车票接口
public interface TrainTicket {
    // 买火车票
    public void getTicket();
}
// 火车站
public class TrainStation implements TrainTicket {
    // 买火车票
    @Override
    public void getTicket() {
        System.out.println("买火车票了!!");
    }
}
// 火车票代售处
public class TrainProxy implements TrainTicket {
    // 目标对象
    private TrainTicket target;
    public TrainProxy(TrainTicket target) {
        this.target = target;
    }
    // 买火车票
    @Override
    public void getTicket() {
        System.out.println("收取手续费!");
        target.getTicket();
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        // 目标对象(火车站,可以直接购买火车票)
        TrainStation trainStation = new TrainStation();
        // 代理对象(代售火车票)
        TrainProxy trainProxy = new TrainProxy(trainStation);
        trainProxy.getTicket();
    }
}
  2)JDK动态代理模式:
// 代售处的程序处理器
public class TicketProxy implements InvocationHandler {
    // 目标对象
    private Object target;
    public TicketProxy(Object target) {
        this.target = target;
    }
    /*
     * 功能:对程序进行处理
     * proxy: 代理对象
     * method: 目标对象的反射对象的方法
     * args: method方法的参数列表
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("收取手续费!!!");
        method.invoke(target, args);   // 调用 target对象中的method方法
        return null;
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        // 火车票
        TrainTicket trainTicket = new TrainStation();
        // 飞机票
        PlaneTicket planeTicket = new Airport();
        // 代售处(动态代理只需要一个代理对象就可以了)
//      InvocationHandler handler = new TicketProxy(trainTicket);  
                // 代售火车票的程序处理器
//      TrainTicket ticketProxy = (TrainTicket) Proxy.newProxyInstance(
//              trainTicket.getClass().getClassLoader(),
//              trainTicket.getClass().getInterfaces(), handler);
//      ticketProxy.getTicket();

        InvocationHandler handler = new TicketProxy(planeTicket);  
                // 代售飞机票的程序处理器
         /*
          * 功能:创建某类的代理对象
          * newProxyInstance(loader, interfaces, handler)
          * loader: 目标类的加载器
          * interfaces: 目标类实现的所有接口反射对象
          * handler: InvocationHandler 程序处理器
          */
         // 创建代理对象(代售处)
        PlaneTicket ticketProxy = (PlaneTicket) Proxy.newProxyInstance(
                planeTicket.getClass().getClassLoader(),
                planeTicket.getClass().getInterfaces(), handler);
        ticketProxy.getTicket();
    }
}
  3)CGlib动态代理模式:
// 火车站
public class TrainStation {
    // 买火车票
    public void getTicket() {
        System.out.println("买火车票了!!");
    }
}
// 代售处的方法拦截器
public class TicketProxy implements MethodInterceptor {
    // Enhancer允许为非接口类型创建一个Java代理。
    // Enhancer动态创建了给定类型的子类但是拦截了所有的方法。
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class cls) {
        // 设置要代理的目标类的class对象 
        enhancer.setSuperclass(cls);
        // 设置回调  
        enhancer.setCallback(this);
        return enhancer.create();   // 创建代理对象
    }
    /*
     * 功能:通过继承的方式拦截父类(目标类)中所有方法
     * obj: 目标对象
     * method: 目标对象的方法
     * args: method方法的参数列表
     * proxy: 代理对象
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        System.out.println("收取手续费!!!");
        // 代理对象调用父类(目标对象)的方法
        proxy.invokeSuper(obj, args);
        return null;
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        // 方法拦截器
        TicketProxy proxy = new TicketProxy();
        // 获取代理对象(代售处)
        TrainStation trainStation = (TrainStation) proxy.getProxy(TrainStation.class);
        trainStation.getTicket();
    }
}
4、静态代理与动态代理的区别:

  静态比较死,动态比较灵活。就比如代售处,如果用静态代理的话,如果需要代售火车票和代售飞机票,那就需要两个代理对象,这样很多代码重复性太高,也会造成代理类膨胀;如果用动态代理,只需要一个代理对象就可以,对不同的类不同的方法进行动态的代理,因为它说白了只是对买票进行代理。

5、CGlib动态代理与JDK动态代理的区别:

  JDK动态代理只能代理实现了某些接口的目标类,如果这个目标类没有实现某些接口,是不能使用JDK动态代理的。

  CGlib动态代理是针对类来实现代理,相当于对指定的目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用,但它不能对final修饰的类进行代理,因为final修饰的类不能被继承。



  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小异常

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值