我是靠谱客的博主 稳重云朵,最近开发中收集的这篇文章主要介绍设计模式(装饰者模式,外观模式,代理模式)装饰者模式外观模式代理模式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

装饰者模式

1.什么是装饰者模式?

2. 术语:

3. 目的:

4.特点:

5. 什么时候使用装饰者模式?

6. 优缺点:

优点:

缺点:

7. 案例:

外观模式

1. 什么是外观模式?

 2. 术语:

3. 目的:

4. 注意事项及细节

5. 什么时候使用外观模式?

6. 优缺点

优点:

缺点:

7.案例:

代理模式

1. 什么是代理模式?

2. 术语:

3. 目的:

4.什么时候使用代理模式?

5.分类:

静态代理

动态代理

6. 案例:

静态代理

动态代理

Cglib代理


装饰者模式

1.什么是装饰者模式?

装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

2. 术语:

Component:组件(主体)
concreteComponent:被装饰者
Decorator:装饰者 

3. 目的:

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活

4.特点:

1. 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。

2. 装饰对象包含一个真实对象的引用(reference)

3. 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。

4. 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

5. 什么时候使用装饰者模式?

在不想增加很多子类的情况下扩展类。

6. 优缺点:

优点:

1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。

2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点:

1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。

2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。

3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

注意:concreteComponent、Decorator都会实现或继承Component

7. 案例:

package com.javaxl.design.decorator.after;

import com.javaxl.design.decorator.before.DrinkSeasoning;

/**
 * @site www.javaxl.com
 * @company
 * @create  2020-02-22 18:27
 * <p>
 * 饮料包括单体咖啡+调料
 */
public abstract class Drink {
    protected double price;
    protected int n;

    public abstract double getPrice();
}

/**
 * 单体咖啡
 */
abstract class Coffee extends Drink {
}

/**
 * 单体果汁
 */
abstract class Juice extends Drink {
}

class ChinaCoffee extends Coffee {
    ChinaCoffee(double price, int n) {
        this.price = price;
        this.n = n;
    }

    @Override
    public double getPrice() {
        return this.price * this.n;
    }
}


package com.javaxl.design.decorator.after;

/**
 * @site www.javaxl.com
 * @company
 * @create  2020-02-22 22:26
 */
public class DecoratorDrink extends Drink {
    private Drink drink;

    public DecoratorDrink(Drink drink, double price, int n) {
        this.drink = drink;
        this.price = price;
        this.n = n;
    }

    @Override
    public double getPrice() {
        return this.price * this.n + drink.getPrice();
    }
}

class ADecoratorDrink extends DecoratorDrink {
    public ADecoratorDrink(Drink drink, double price, int n) {
        super(drink, price, n);
    }
}

class BDecoratorDrink extends DecoratorDrink {
    public BDecoratorDrink(Drink drink, double price, int n) {
        super(drink, price, n);
    }
}


package com.javaxl.design.decorator.after;


/**
 * @site www.javaxl.com
 * @company
 * @create  2020-02-22 18:50
 */
public class Client {
    public static void main(String[] args) {
        ChinaCoffee chinaCoffee = new ChinaCoffee(6,1);
//        假定A类调料2元一份,B类调料3元一份
        Drink order = new ADecoratorDrink(chinaCoffee, 2, 2);
        System.out.println("中式咖啡1份+A调料2份,最终价格为:"+order.getPrice());

//        思考1:如果我要下单中式咖啡1份+A调料3份+B调料2份,计算出最终的价格,那代码该怎么改动呢?
        order = new ADecoratorDrink(order,2,1);
        System.out.println("式咖啡1份+A调料3份,最终价格为:"+order.getPrice());
        order = new BDecoratorDrink(order,3,2);
        System.out.println("式咖啡1份+A调料3份+B调料2份,最终价格为:"+order.getPrice());

//        思考2:在原有的咖啡订单下,追加B调料2份,计算出最终的价格,那代码该怎么改动呢?
        order = new BDecoratorDrink(order,3,2);
        System.out.println("式咖啡1份+A调料3份+B调料4份,最终价格为:"+order.getPrice());
    }
}

外观模式

1. 什么是外观模式?

外观模式(Facade),亦称“过程模式”。学校课程评价模式之一。美国教育学者斯泰克1967 年在所著《教育评价的外观》中提出。主张按照描述和判断资料来评价课程,关键的活动是在课程实施的全过程中进行观察和搜集意见,以了解人们对课程的不同看法。这种模式不限于检查教学的成果,重视描述和判断教学过程中各种复杂、动态的现象和事物。

 2. 术语:

Facade:外观

3. 目的:

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。降低访问复杂系统的内部子系统时的复杂度,简化客户端之间的接口。

4. 注意事项及细节

1. 屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性

2. 对客户端与子系统的耦合关系 - 解耦,让子系统内部的模块更易维护和扩展

3. 当系统需要进行分层设计时,可以考虑使用 Facade 模式

5. 什么时候使用外观模式?

1、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。

2、定义系统的入口。

6. 优缺点

优点:

(1)实现了子系统与客户端之间的松耦合关系。

(2)客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易

缺点:

不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

注:在层次化结构中,可以使用外观模式定义系统中每一层的入口。

7.案例:

客户端调用依赖了所有的子系统(ABCDE),如果该需求反复出现,对于客户端调用而言,就不是很方便了;

另一方面,此需求完成只需要依赖各个子系统的其中一部分功能,其它功能客户端用不上,依照迪米特法则我们也应该解耦客户端与各个子系统的关系;

package com.javaxl.design.facade.after;

/**
 * @site www.javaxl.com
 * @company
 * @create  2020-02-23 16:29
 *
 * 电脑(故意写两个用不上的功能,依次体现外观模式的优点)
 */
public class ComponentA {
    public void m1(){
        System.out.println("电脑功能一...");
    }
    public void m2(){
        System.out.println("电脑功能二...");
    }

    public void on(){
        System.out.println("电脑打开...");
    }

    public void off(){
        System.out.println("电脑关闭...");
    }
}

//投影仪
class ComponentB {
    public void on(){
        System.out.println("投影仪打开...");
    }

    public void off(){
        System.out.println("投影仪关闭...");
    }
}

//音箱
class ComponentC {
    public void on(){
        System.out.println("音箱打开...");
    }

    public void off(){
        System.out.println("音箱关闭...");
    }
}

//、灯光
class ComponentD {
    public void on(){
        System.out.println("灯光调亮...");
    }

    public void off(){
        System.out.println("灯光调暗...");
    }
}

//零食
class ComponentE {
    public void on(){
        System.out.println("零食拿出来...");
    }

    public void off(){
        System.out.println("零食收起来...");
    }
}


public class ComponentFacade {
    ComponentA componentA =new ComponentA();
    ComponentB componentB = new ComponentB();
    ComponentC componentC = new ComponentC();
    ComponentD componentD = new ComponentD();
    ComponentE componenE = new ComponentE();
    public void on(){
        componentA.on();
        componentB.on();
        componentC.on();
        componentD.off();
        componenE.on();
        System.out.println("电影开始了...");
    }

    public void off(){
        componenE.off();
        componentD.on();
        componentC.off();
        componentB.off();
        componentA.off();
        System.out.println("电影结束了...");
    }
}


public class Client {
    public static void main(String[] args) {
        ComponentFacade componentFacade = new ComponentFacade();
        componentFacade.on();
        System.out.println();
        componentFacade.off();
    }
}

代理模式

1. 什么是代理模式?

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

2. 术语:

Proxy:代理

3. 目的:

为其他对象提供一种代理以控制对这个对象的访问。

4.什么时候使用代理模式?

想在访问一个类时做一些控制。

5.分类:

静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类

优点:

在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展

缺点:

因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类

一旦接口增加方法,目标对象与代理对象都要维护

动态代理

  1. 代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
  2. 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象
  3. 动态代理也叫做:JDK代理、接口代理

jdk代理与Cglib代理比较:

JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高

​ 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

6. 案例:

静态代理

 


package com.javaxl.design.proxy.staticproxy;

/**
 * @site www.javaxl.com
 * @company
 * @create  2020-02-24 9:35
 * <p>
 * 目标类
 */
public class TeacherDAO implements ITeacherDao {
    public void teach() {
        System.out.println("老师传授知识");
    }
}

//目标接口
interface ITeacherDao {
    void teach();
}

//代理类
class TeacherDAOProxy implements ITeacherDao {
    private ITeacherDao teacherDAO;

    public TeacherDAOProxy(ITeacherDao teacherDAO) {
        this.teacherDAO = teacherDAO;
    }

    @Override
    public void teach() {
        System.out.println("老师正式授课前的准备工作,如学生全部签到...");
        teacherDAO.teach();
        System.out.println("老师结束授课,如下课铃声响起...");
    }
}


public class Client {
    public static void main(String[] args) {
        TeacherDAOProxy proxy = new TeacherDAOProxy(new TeacherDAO());
        proxy.teach();
    }
}

动态代理


/**
 * 目标接口
 */
interface ITeacherDao {
    String teach();

    ITeacherDao sleep(int minutes);
}

class TeacherDao implements ITeacherDao{
    @Override
    public String teach() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date())+":老师传授知识";
    }

    @Override
    public ITeacherDao sleep(int minutes) {
        System.out.println("老师睡了" + minutes + "分钟");
        return this;
    }

}

//真实代理类的外衣
class TeacherDaoProxy{
    private ITeacherDao target;

    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }

    public Object xxx(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object obj = null;
                        String methodName = method.getName();
                        System.out.println("目标方法" + methodName + ":jdk代理开始...");
                        System.out.println("真实代理对象:"+proxy.getClass());
                        System.out.println("目标对象:"+target.getClass());
                        if("sleep".equals(methodName)){
//                            method.invoke(target, args);
//                            obj = proxy;
                            obj = method.invoke(target, args);
                        }else {
//                        proxy是真实代理类,method是目标方法,args是目标方法携带的参数
                            obj = method.invoke(target, args);
                        }
                        System.out.println("目标方法" + methodName + ":jdk代理结束...");
                        return obj;
                    }
                });
    }
}


public class Client {
    public static void main(String[] args) {
        TeacherDaoProxy proxy = new TeacherDaoProxy(new TeacherDao());
        ITeacherDao ins = (ITeacherDao) proxy.xxx();
        System.out.println("===========代理类实例被使用   begin=============");
        System.out.println(ins);
        System.out.println("===========代理类实例被使用   end=============");
        System.out.println(ins.teach());
//        System.out.println(proxy.execute());
        System.out.println("===========代理类实例被使用   begin=============");
        ins.sleep(10);
        System.out.println("===========代理类实例被使用   end=============");
        ins.sleep(20).sleep(60);
    }
}

Cglib代理

 

class TeacherDao {
    public String teach() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date()) + ":老师传授知识";
    }

    public TeacherDao sleep(int minutes) {
        System.out.println("老师睡了" + minutes + "分钟");
        return this;
    }

}

//真实代理类的外衣
class TeacherDaoProxy implements MethodInterceptor {
    private Object target;

    public TeacherDaoProxy(Object target) {
        this.target = target;
    }

    //返回一个代理对象:	是 target  对象的代理对象
    public Object getProxyInstance() {
        //1. 创建一个工具类
        Enhancer enhancer = new Enhancer();
        //2. 设置父类
        enhancer.setSuperclass(target.getClass());
        //3. 设置回调函数
        enhancer.setCallback(this);
        //4. 创建子类对象,即代理对象
        return enhancer.create();
    }

    /**
     * @param proxyIns  由CGLib动态生成的代理类实例
     * @param method    上文中实体类所调用的被代理的方法引用
     * @param args      参数值列表
     * @param methodProxy   生成的代理类对方法的代理引用
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxyIns, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        String methodName = method.getName();
        Object res;
        System.out.println("目标方法" + methodName + ":cglib代理开始...");
        System.out.println("真实代理对象:" + proxyIns.getClass());
        System.out.println("目标对象:" + target.getClass());
        if ("sleep".equals(methodName)) {
//                            method.invoke(target, args);
//                            obj = proxy;
            res = method.invoke(target, args);
//            res = methodProxy.invokeSuper(proxyIns,args);
            res = proxyIns;
        } else {
//                        proxy是真实代理类,method是目标方法,args是目标方法携带的参数
            res = method.invoke(target, args);
        }
        System.out.println("目标方法" + methodName + ":cglib代理结束...");
        return res;
    }
}

public class Client {
    public static void main(String[] args) {
        TeacherDao proxy = (TeacherDao) new TeacherDaoProxy(new TeacherDao()).getProxyInstance();
        proxy.sleep(111).sleep(222);
    }
}

最后

以上就是稳重云朵为你收集整理的设计模式(装饰者模式,外观模式,代理模式)装饰者模式外观模式代理模式的全部内容,希望文章能够帮你解决设计模式(装饰者模式,外观模式,代理模式)装饰者模式外观模式代理模式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部