设计模式阶段一-模板、代理模式相关解析

上一篇博客讲了一下单例和工厂模式,这两种设计模式,我个人感觉讲的还算是比较容易理解的,不过暂时不理解其实也没有啥问题,总归是需要个过程的。

初期想用的时候,其实直接按照例子套用模板公式就可以了,代码写的多了,有了一定的源码阅读量之后,相对来说,就是比较容易理解了,到时候也算是能够有自己一定的心得体会了。

好了,废话不多说,咱们先来说说今天要讲的第一个设计模式-模板方法模式。

##模板方法
假设现在有一批豪车的模型需要建造,一种是宝马,一种是奔驰,订购商要求呀,模型车在启动的时候,需要有点火、鸣笛、熄火三个步骤,按照程序构造,我们写出了如下的代码:

首先我们定义名车的接口类ICar:

/***
 * @desc 汽车类接口
 * @author Aby
 * @date 2020/07/26
 */
public abstract class ICar {

    /***
     * 点火
     */
    public abstract void start();

    /***
     * 熄火
     */
    public abstract void stop();

    /***
     * 鸣笛
     */
    public abstract void alarm();


    /***
     * 启动
     */
    public abstract void run();
}

然后对应的奔驰实现类BenzCar:

/***
 * @desc 奔驰
 * @author Aby
 * @date 2020/07/26
 */
public class BenzCar extends ICar {
    @Override
    public void start() {
        System.out.println("奔驰车发动");
    }

    @Override
    public void stop() {
        System.out.println("奔驰车停止");
    }

    @Override
    public void alarm() {
        System.out.println("奔驰车鸣笛");
    }

    @Override
    public void run() {
        this.start();
        this.alarm();
        this.stop();
    }
}

对应的宝马实现类BmvCar :

/***
 * @desc 宝马
 * @author Aby
 * @date 2020/07/26
 */
public class BmvCar extends ICar {
    @Override
    public void start() {
        System.out.println("宝马车发动");
    }

    @Override
    public void stop() {
        System.out.println("宝马车停止");
    }

    @Override
    public void alarm() {
        System.out.println("宝马车鸣笛");
    }

    @Override
    public void run() {
        this.start();
        this.alarm();
        this.stop();
    }
}

然后是对应的测试类App:

public class App {

    public static void main(String[] args) {
        BenzCar benzCar = new BenzCar();
        benzCar.run();

        BmvCar bmvCar = new BmvCar();
        bmvCar.run();
    }
}

执行测试类,我们能够看到打印出了对应的发动、鸣笛、熄火的三个过程,但是仔细看看我们的宝马类和奔驰类,run方法的代码,完全是重复的,所以这一点儿,我们完全可以将这块儿的代码提出来,所以改造如下:

名车的接口类ICar修改如下:

/***
 * @desc 汽车类接口
 * @author Aby
 * @date 2020/07/26
 */
public abstract class ICar {

    /***
     * 发动
     */
    public abstract void start();

    /***
     * 停止
     */
    public abstract void stop();

    /***
     * 鸣叫
     */
    public abstract void alarm();

    /***
     * 启动
     */
    public final void run() {
        this.start();
        this.alarm();
        this.stop();
    }
}

奔驰实现类BenzCar修改如下:

/***
 * @desc 奔驰
 * @author Aby
 * @date 2020/07/26
 */
public class BenzCar extends ICar {
    @Override
    public void start() {
        System.out.println("奔驰车发动");
    }

    @Override
    public void stop() {
        System.out.println("奔驰车停止");
    }

    @Override
    public void alarm() {
        System.out.println("奔驰车鸣笛");
    }

}

宝马实现类BmvCar修改如下 :

/***
 * @desc 宝马
 * @author Aby
 * @date 2020/07/26
 */
public class BmvCar extends ICar {
    @Override
    public void start() {
        System.out.println("宝马车发动");
    }

    @Override
    public void stop() {
        System.out.println("宝马车停止");
    }

    @Override
    public void alarm() {
        System.out.println("宝马车鸣笛");
    }

}

对应的测试类App我们不做修改:

public class App {
    public static void main(String[] args) {
        BenzCar benzCar = new BenzCar();
        benzCar.run();

        BmvCar bmvCar = new BmvCar();
        bmvCar.run();
    }
}

重新执行对应的测试类,我们能够发现代码完全是没有问题的,依然能够得到我们想要的结果。

而这种抽出来共同点,交给具体子类来实现具体细节的方法,就是所谓的模板方法了,这种设计模式其实用的还是挺多的,在spring和mybatis我们常用的两种框架中运用的也是到处都是,这一点儿等到下次更新博文的时候,会进行详细的说明。

好了,模板方法讲完了,接下来我们就来说说代理模式了。

代理模式

生活在社会中,我们很多时候都是会遇到各种各样的问题,比如买房这种事情,现在房价越来越贵,想买一套房子基本上掏空三代人,甚至于一二三线城市,即便是掏空三代人说不定也付不起个首付,就说我吧,从毕业还没有开始就在南京混,现在工作了五年了,还是买不起南京的一套房,其中缘由自不必说,毕竟说多了咱怕和谐,言多必失还是很有道理的。

好了,不扯了,咱们就从买房这件事情来说吧,想要买房需要了解各种政策,而且真正买房之后,假如说是买套二手房,还需要校验一系列原房主的身份产权等等,再加上去银行贷款,各种杂七杂八的事情,一般人想搞懂也不容易,所以这个时候,我们可以找一个中介,让中介来搞定中间的一系列环节,到时候想买房只需要签个字就可以了。而中介的做的事情,其实就是代理的一种过程。

静态代理

好了,我们按照上面的思路,来进行代码的编写,咱们先看不用代理的时候的代码:

首先定义一个人购买房子的接口IPerson:

/***
 * @desc 买房接口
 * @author Aby
 * @date 2020/07/26
 */
public interface IPerson {

    /***
     * 买房的方法
     * @param userName 用户
     */
    void buyHouse();
}

具体的实现类Person:

/***
 * @desc 具体买房类
 * @author Aby
 * @date 2020/07/26
 */
public class Person implements IPerson {

    private String userName;

    public Person(String userName) {
        this.userName = userName;
    }

    @Override
    public void buyHouse() {
        System.out.println(this.userName + "买房");
    }
}

测试类App:

public class App {

    public static void main(String[] args) {
        IPerson person = new Person("张三");
        person.buyHouse();
    }
}

执行对应的测试类,我们能够看到,打印出了张三买房的过程。

上面的实现,是没有使用代理的,那么我们现在使用下代理的模式进行代码开发:

首先以上的接口和实现类,都不改变,我们新增代理类ProxyPerson:

/***
 * @desc 代理类
 * @author Aby
 * @date 2020/07/26
 */
public class ProxyPerson implements IPerson {
    private IPerson iPerson = null;
    public ProxyPerson(IPerson _iPerson) {
        this.iPerson = _iPerson;
    }
    @Override
    public void buyHouse() {
        this.iPerson.buyHouse();
    }
}

然后我们修改下对应的App测试类:

public class App {
    public static void main(String[] args) {
        IPerson person = new Person("张三");
        ProxyPerson proxyPerson = new ProxyPerson(person);
        proxyPerson.buyHouse();
    }
}

运行测试类,我们能够看到,打印出的与之前是一样的,而这就是代理,代理的意义就是不用自己亲力亲为,只需要指定对应的人去处理即可,在我们的生活场景中,其实处处是代理,买房、代练游戏、搬运,各种杂七杂八的不一而足,不过我们之前的代码,实现的只是最简单的一种代理模式,这种模式常常被称为静态代理。

有静态代理,那么自然是有动态代理,我们下面就来说说动态代理。

动态代理

动态代理实现的方式以我所知的,就是两种,一种是实现InvocationHandler接口,一种是cglib实现,cglib的这种我们就不说了,我们这次主要是来说说实现InvocationHandler接口的代理。

如同上面的静态代理,如果说我们有很多的接口,都需要产生代理类的话,那么对应的代理类就是很多,这导致代码量不断增加,但是做的事情其实都是差不多的,所以这个时候动态代理自然是孕育而生。

首先新增动态代理类PersonInvocationHandler:

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

/***
 * @desc 动态代理类
 * @author Aby
 * @date 2020/07/26
 */
public class PersonInvocationHandler implements InvocationHandler {
    //被代理者
    Class cls = null;
    //被代理的实例
    Object obj = null;

    //需要代理的
    public PersonInvocationHandler(Object _object) {
        this.obj = _object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(this.obj, args);
        return result;
    }
}

改造对应的App测试类:

import java.lang.reflect.Proxy;

public class App {

    public static void main(String[] args) {
        IPerson person = new Person("张三");
        PersonInvocationHandler invocationHandler = new PersonInvocationHandler(person);
        //获得类的class loader
        ClassLoader cl = person.getClass().getClassLoader();
        //动态产生一个代理者
        IPerson proxy = (IPerson) Proxy.newProxyInstance(cl, person.getClass().getInterfaces(), invocationHandler);
        proxy.buyHouse();
    }
}

执行以上的代码,我们能够看到,同样的能够实现我们想要的方法,而且上面的代理类,不仅仅能够代理买房这个接口,还能够代理其他的各种接口。

以上就是InvocationHandler实现的动态代理了,cglib咱们这里就不说了,不过最基本的差异点我们要了解,就是InvocationHandler代理的是接口,cglib是不需要的,而且InvocationHandler和cglib代理的方式也不一样,这个以后有机会再说。

好了,这就是今天说的模板方法模式和代理模式了,其实设计模式不需要太过刻意去用,其实有句话说的好:“看山是山;看山不是山;看山还是山。”真正的高手是运用起设计模式并不是刻意去用的,而是写出来代码,自然而然的就成为设计模式了,说实话这种牛人我倒是认识一个,可惜人家不认识我哈。

好了,这一篇博文到这里就结束了,下一讲我们就来看看,这两篇讲的设计模式在一些流行框架中的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值