【归纳总结】Spring之设计模式(单例、工厂、代理、建造者)

设计模式的六大原则:

  1. 单一职责:一个类和方法只做一件事
  2. 开闭原则:对新增代码开放,对修改代码封闭
  3. 里氏替换:子类不要覆盖父类的方法(抽象方法除外)
  4. 接口隔离:不要在一个接口里面放很多的方法
  5. 依赖倒置:依赖关系是通过接口或抽象类产生的
  6. 迪米特法则:尽量降低类与类之间的耦合

单例模式

1️⃣核心思想

应用程序运行过程中,获得某一个类型的实例的时候,获得的始终是同一个实例

分为三步:

  1. 构造方法私有
  2. 自身提供一个实例
  3. 提供一个静态方法供外部类获取该类的对象

2️⃣模式实现

  • 懒加载:需要的时候就加载,当我们去调用到获得实例方法的才进行加载。

  • 立即加载:马上加载,在我们获得实例之前已经完成加载。

①线程不安全的懒加载

public class MySingleton01 {

    //自身提供一个实例
    private static MySingleton01 mySingleton01;

    //提供一个静态方法给外部类获得实例
    public static MySingleton01 getInstance(){
        //没有实例化则实例化
        if (mySingleton01 == null){
            mySingleton01 = new MySingleton01();
        }
        //已实例化则直接返回
        return mySingleton01;
    }

    //构造方法私有
    private MySingleton01(){}
}

②线程安全的懒加载

给获得实例的方法加个锁即可

public class MySingleton02 {

    //自身提供一个实例
    private static MySingleton02 mySingleton02;

    //提供一个静态方法给外部类获得实例
    public synchronized static MySingleton02 getInstance(){
        //没有实例化则实例化
        if (mySingleton02 == null){
            mySingleton02 = new MySingleton02();
        }
        //已实例化则直接返回
        return mySingleton02;
    }

    //构造方法私有
    private MySingleton02(){}
}

③线程安全的立即加载

立即加载都是线程安全的,因为对象只会在类加载的时候创建

package singleton;

public class MySingleton03 {

    //自身提供一个实例
    private static MySingleton03 mySingleton03 = new MySingleton03();

    //提供一个静态方法给外部类获得实例
    public static MySingleton03 getInstance(){
        return mySingleton03;
    }

    //构造方法私有
    private MySingleton03(){}
}

④线程安全的立即加载(内部类)

package singleton;

public class MySingleton04 {

    //提供一个静态方法给外部类获得实例
    public static MySingleton04 getInstance(){
        return Inner.mySingleton04;
    }

    private static class Inner{
        //自身提供一个实例
        public static MySingleton04 mySingleton04 = new MySingleton04();
    }

    //构造方法私有
    private MySingleton04(){}
}


工厂模式

1️⃣核心思想

定义一个创建对象的接口。让子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类中进行

2️⃣模式实现

在这里插入图片描述
在接口中定义一个创建工厂类的方法

public interface CarFactory {
    public Car creatCar();
}

在具体工厂中创建要对应的工厂类

public class TeslaFactory implements CarFactory{
    public Car creatCar() {
        return new TeslaCar();
    }
}

代理模式

1️⃣核心思想

代理类实现了委托类要做的事,并且在做这些事的前后都可以做额外的事(增强)

2️⃣模式实现

①静态代理

委托类:

public class Client {
    public void buyBreakfast(){
        System.out.println("一碗热干面");
    }
}

代理类继承委托类:

public class Agent extends Client {
    @Override
    public void buyBreakfast(){
        super.buyBreakfast();
        System.out.println("一杯蛋酒");
    }
}

②动态代理

动态代理不需要新建代理类就可以获得代理类的对象

Ⅰ.JDK动态代理

使用条件:委托类必须实现一个接口,因为用该方法生成的代理对象也会继承该接口,并且只能代理执行该接口中定义的方法。

使用方法

  1. 调用Proxy.newProxyInstance(param1,param2,param3)方法,该方法需要三个参数,第一个是类加载器,第二个是接口的Class类,第三个是实现了InvocationHandler接口的对象,第三个参数可以使用内部类的方式。
  2. 这样就得到了一个与委托类实现了相同接口的代理对象在该对象上调用方法就相当于调用InvocationHandler对象中的invoke()方法
  3. 因此我们可以在invoke()方法中执行委托类的方法,并且可以在invoke()方法中做额外的事,这样,代理类在调用任何方法的时候,都会执行在invoke()方法中额外做的事情

使用案例
假如现有接口BuyFood:

public interface BuyFood {
    public String buyLunch(String food);
}

Client类实现了该接口:

public class Client implements BuyFood {
    public String buyLunch(String food){
        System.out.println(food);
        return food;
    }
}

获得代理类的对象并调用方法:

public class JDKDynamic {
    public static void main(String[] args) {

        BuyFood proxy = (BuyFood) Proxy.newProxyInstance(Client.class.getClassLoader(), Client.class.getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("一根油条");
                Object invoke = method.invoke(Client.class.newInstance(), args);
                System.out.println("一杯豆浆");
                return invoke;
            }
        });

        String s = proxy.buyLunch("一碗炒粉");
        System.out.println("------------");
        System.out.println(s);
    }
}

输出结果为:

一根油条
一碗炒粉
一杯豆浆
------------
一碗炒粉
Ⅱ.cglib动态代理

使用条件
导入依赖:

 <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.2.12</version>
</dependency>

使用方法

  1. 调用Enhance.create(param1, param2)方法,该方法需要两个参数,第一个是委托类的Class类,第二个是实现了InvocationHandler接口的对象。特别注意:这个接口与JDK动态代理的InvocationHandler接口名字相同,但是包不同,所以不是同一个接口
  2. 这样就得到了一个继承自委托类,并重写了委托类所有方法的对象
  3. 后续与JDK动态代理一样。

使用案例
有如下委托类没有实现任何接口:

public class Client {
    public String buyLunch(String food){
        System.out.println(food);
        return food;
    }
}

获得代理类并调用其方法:

public class CglibDynamic {
    public static void main(final String[] args) {
        Client proxy = (Client) Enhancer.create(Client.class, new InvocationHandler() {
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("一瓶可乐");
                Object invoke = method.invoke(Client.class.newInstance(), objects);
                System.out.println("一根烤肠");
                return invoke;
            }
        });
        String s = proxy.buyLunch("一个汉堡");
        System.out.println("----------");
        System.out.println(s);
    }
}

输出结果为:

一瓶可乐
一个汉堡
一根烤肠
----------
一个汉堡

建造者模式

1️⃣核心思想

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
通俗来说,将方法的返回值设为该对象即可。

2️⃣模式实现

假如现在造一个人,有头、手、腿三部分,头分为IQ、EQ、头发,手和腿有长度
创建HumanBuilder:

public class HumanBuilder {
    private Human human = new Human();

    public HumanBuilder setHeadIQ(Integer IQ){
        Head head = human.getHead();
        head.setIQ(IQ);
        return this;
    }

    public HumanBuilder setHeadEQ(Integer EQ){
        Head head = human.getHead();
        head.setEQ(EQ);
        return this;
    }

    public HumanBuilder setHeadHair(String hair){
        Head head = human.getHead();
        head.setHair(hair);
        return this;
    }

    public HumanBuilder setArmLen(Integer len){
        Arm arm = human.getArm();
        arm.setLen(len);
        return this;
    }

    public HumanBuilder setLegLen(Integer len){
        Leg leg = human.getLeg();
        leg.setLen(len);
        return this;
    }

    public Human build(){
        return human;
    }
}

测试:

@Test
    public void test01(){
        HumanBuilder hb = new HumanBuilder();
        hb.setHeadIQ(100).setHeadEQ(99).setHeadHair("black").setArmLen(70).setLegLen(90);
        Human build = hb.build();
        System.out.println(build);
    }

测试结果:

Human(head=Head(IQ=100, EQ=99, hair=black), arm=Arm(len=70), leg=Leg(len=90))
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值