0
点赞
收藏
分享

微信扫一扫

结构型模式

心智的年轮 2022-04-19 阅读 38
代理模式

目录

1、适配器模式(Adapter)

 2、结构性模式案例

3、桥接模式 

4、装饰者模式(Decorator) 

 5、外观模式(Facade)

6、 代理模式(Proxy)


1、适配器模式(Adapter)


 

 2、结构性模式案例

 - 使用前

    ```
    package com.javaxl.design.adapter.before;
    
    /**
     * @author 小李飞刀
     * @site www.javaxl.com
     * @company
     * @create  2020-02-22 15:51
     *
     * 220V的电压
     */
    public class Voltage220V {
        private double voltage;
    
        public Voltage220V() {
            this.voltage = 220;
        }
    
        public double getVoltage() {
            return voltage;
        }
    
        public void setVoltage(double voltage) {
            this.voltage = voltage;
        }
    }
    
    
    public class Phone {
    //    充电
        public void charge(Voltage220V voltage220V){
            double voltage = voltage220V.getVoltage() / 40;
            System.out.println("最终手机充电所用电压:" + voltage + "V");
        }
    }
    
    
    public class Client {
        public static void main(String[] args) {
            Phone phone = new Phone();
    //        已知有一个220V的电源,要用它给手机进行充电,我们只能将220V的电源进行处理后才能给手机充上电
    //        还一种方案:新增5V的一个Voltage5V,Voltage的电压可以被手机使用
    //        但是这违背现实生活现象,现实生活中只有220V的电源,其他的电源都是通过适配得来的
            phone.charge(new Voltage220V());
        }
    }
 - 使用后
/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2020-02-22 15:51
 *
 * 220V的电压
 */
public class Voltage220V {
    private double voltage;

    public Voltage220V() {
        this.voltage = 220;
    }

    public double getVoltage() {
        return voltage;
    }

    public void setVoltage(double voltage) {
        this.voltage = voltage;
    }
}

/**
 * 目标接口
 */
interface Voltage5V{
    double getVoltage();
}

/**
 * 适配器:里面封装了source源到destination目标的过程
 */
class VoltageAdapter implements  Voltage5V{
    private Voltage220V voltage220V;

    public VoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public double getVoltage() {
        return voltage220V.getVoltage() / 40;
    }
}


package com.javaxl.design.adapter.after;


public class Phone {
//    充电
    public void charge(Voltage5V voltage5V){
        double voltage = voltage5V.getVoltage();
        System.out.println("最终手机充电所用电压:" + voltage + "V");
    }
}


public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone();
//        已知有一个220V的电源,要用它给手机进行充电,我们只能将220V的电源进行处理后才能给手机充上电
//        VoltageAdapter适配器对Voltage220V这个不能直接使用的电源适配后就可以使用了
        phone.charge(new VoltageAdapter(new Voltage220V()));
    }
}

 

3、桥接模式 

案例 

 

package com.javaxl.design.bridge;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2020-02-22 17:29
 * <p>
 * 手机型号
 */
public abstract class Abstraction {
    protected Implementor implementor;

    public abstract void call();
}

class Folded extends Abstraction {
    private String name = "折叠式";

    Folded(Implementor implementor) {
        this.implementor = implementor;
    }

    @Override
    public void call() {
        System.out.println(this.implementor.getName() + this.name + "正在通话中");
    }
}

class Upright extends Abstraction {
    private String name = "直立式";

    Upright(Implementor implementor) {
        this.implementor = implementor;
    }

    @Override
    public void call() {
        System.out.println(this.implementor.getName() + this.name + "正在通话中");
    }
}

class Slide extends Abstraction {
    private String name = "滑盖式";

    Slide(Implementor implementor) {
        this.implementor = implementor;
    }

    @Override
    public void call() {
        System.out.println(this.implementor.getName() + this.name + "正在通话中");
    }
}
/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2020-02-22 17:29
 * 手机品牌
 */
public interface Implementor {
    String getName();
}

class HW implements Implementor{
    private String name = "华为";

    @Override
    public String getName() {
        return name;
    }
}

class Mi implements Implementor{
    private String name = "小米";

    @Override
    public String getName() {
        return name;
    }
}

class Vivo implements Implementor{
    private String name = "Vivo";

    @Override
    public String getName() {
        return name;
    }
}


public class Client {
    public static void main(String[] args) {
        Folded folded = new Folded(new HW());
        folded.call();

        Upright upright = new Upright(new Mi());
        upright.call();

        Slide slide = new Slide(new Vivo());
        slide.call();
    }
}

 

4、装饰者模式(Decorator)
 

案例:单体咖啡与调味组合的饮料计价项目

 - 使用前

  

  这个项目最容易想到的设计方案就是采用继承的设计方案,设计思路如下:

  ​	Drink===》饮品

  ​		Juice===》果汁

  ​			.......

  ​		Coffee===》咖啡

  ​			ChinaCoffee===》中式咖啡

  ​				ASeasoningChinaCoffee===》被A调料修饰的中式咖啡

  ​				BSeasoningChinaCoffee===》被B调料修饰的中式咖啡

  ​				......

  ​			XxxCoffee===》其它咖啡

  ​				ASeasoningXxxCoffee===》被A调料修饰的其它咖啡

  ​				BSeasoningXxxCoffee===》被B调料修饰的其它咖啡

  ​				......

  上面每个类中都有getPrice计价的功能,从结果上来看,确实可以完成项目需求,但是整个设计体系过于臃肿,不便于后期的扩展与维护;

  

  用前面的桥接模式来进行设计,可以解决体系臃肿问题

  ```
  package com.javaxl.design.decorator.before;
  
  /**
   * @author 小李飞刀
   * @site www.javaxl.com
   * @company
   * @create  2020-02-22 18:27
   *
   * 饮料包括单体咖啡+调料
   */
  public abstract class Drink {
      protected double price;
      protected int n;
      protected DrinkSeasoning seasoning;
  
      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+this.seasoning.getPrice();
      }
  }
  
  
  package com.javaxl.design.decorator.before;
  
  /**
   * @author 小李飞刀
   * @site www.javaxl.com
   * @company
   * @create  2020-02-22 18:32
   *
   * 调料的抽象接口
   */
  public interface DrinkSeasoning {
      public abstract double getPrice();
  }
  
  /**
   * A类调料
   */
  class ADrinkSeasoning implements  DrinkSeasoning{
      protected double price;
      protected int n;
      ADrinkSeasoning(double price,int n){
          this.price = price;
          this.n = n;
      }
      @Override
      public double getPrice() {
          return this.price*this.n;
      }
  }
  
  
  /**
   * B类调料
   */
  class BDrinkSeasoning implements  DrinkSeasoning{
      private double price;
      protected int n;
      BDrinkSeasoning(double price,int n){
          this.price = price;
          this.n = n;
      }
      @Override
      public double getPrice() {
          return this.price*this.n;
      }
  }
  
  
  public class Client {
      public static void main(String[] args) {
          ChinaCoffee chinaCoffee = new ChinaCoffee(6,1);
          ADrinkSeasoning aDrinkSeasoning = new ADrinkSeasoning(2,2);
          chinaCoffee.seasoning = aDrinkSeasoning;
          System.out.println("中式咖啡1份+A调料2份,最终价格为:"+chinaCoffee.getPrice());
  
  //        思考1:如果我要下单中式咖啡1份+A调料3份+B调料2份,计算出最终的价格,那代码该怎么改动呢?
  //        思考2:在原有的咖啡订单下,追加B调料2份,计算出最终的价格,那代码该怎么改动呢?
      }
  }
 - 使用后

使用装饰模式进行设计
代码逻辑如下

  ```
package com.javaxl.design.decorator.after;

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

/**
 * @author 小李飞刀
 * @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;

/**
 * @author 小李飞刀
 * @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;


/**
 * @author 小李飞刀
 * @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());
    }
}

 5、外观模式(Facade)

 案例:

 

/**
 * @author 小李飞刀
 * @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 ComponenE {
    public void on(){
        System.out.println("零食拿出来...");
    }

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


public class Client {
    public static void main(String[] args) {
        new ComponentA().on();
        new ComponentB().on();
        new ComponentC().on();
        new ComponentD().off();
        new ComponenE().on();
        System.out.println("电影开始了...");

        System.out.println();
        new ComponenE().off();
        new ComponentD().on();
        new ComponentC().off();
        new ComponentB().off();
        new ComponentA().off();
        System.out.println("电影结束了...");
    }
}

 

  - 使用后

类图设计
/**
 * @author 小李飞刀
 * @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();
    }
}

```

从上面可以看出,客户端只依赖了外观类,彻底解耦了与各个子系统之间的关系;

外观模式的应用场景 

 


6、 代理模式(Proxy)

 案例

/**
   * @author 小李飞刀
   * @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();
      }
  }
  

  6.1- 动态代理

 案例

  ```
    package com.javaxl.design.proxy.dynamic.jdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * 目标接口
     */
    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);
        }
    }
    
    ```

注意:java.lang.reflect.InvocationHandler.invoke第一个参数proxy的使用场景,链式编程中会用到;


 6.2Cglib代理

案例:

```
package com.javaxl.design.proxy.dynamic.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;


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);
    }
}

```
举报

相关推荐

0 条评论