设计模式 ---- 七种结构性型设计模式

Posted wdxjy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 ---- 七种结构性型设计模式相关的知识,希望对你有一定的参考价值。

                  七种结构性设计模式

 

1.适配器模式

技术图片

 

 

 目的:在java中的目的就是为了,让不兼容的类进行兼容。

分类:类适配器模式,对象适配器模式,接口适配器模式。

1.1类适配器

还是以这个插座的适配器我们来做分析,看一下这个例子:

技术图片

 

 

 对于220V的电压我们是不能直接使用的,因此我们需要通过一个适配器将他转换

使用适配器模式

技术图片

 

 

 

原本的类:

package com.atguigu.adapter.classadapter;

//被适配的类
public class Voltage220V {
    //输出220V的电压
    public int output220V() {
        int src = 220;
        System.out.println("电压=" + src + "");
        return src;
    }
}

这是适配器类,实现类中只有一个output方法:

package com.atguigu.adapter.classadapter;

//适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {

    @Override
    public int output5V() {
        // TODO Auto-generated method stub
        //获取到220V电压
        int srcV = output220V();
        int dstV = srcV / 44 ; //转成 5v
        return dstV;
    }

}

这就是类适配器的使用

1.2对象适配器

对于类适配器没有太多改变。

主要是没有去继承了,改用聚合

package com.atguigu.adapter.objectadapter;

//适配器类
public class VoltageAdapter  implements IVoltage5V {

    private Voltage220V voltage220V; // 关联关系-聚合    看这一行


//通过构造器,传入一个 Voltage220V 实例 public VoltageAdapter(Voltage220V voltage220v) { this.voltage220V = voltage220v; } @Override public int output5V() { int dst = 0; if(null != voltage220V) { int src = voltage220V.output220V();//获取220V 电压 System.out.println("使用对象适配器,进行适配~~"); dst = src / 44; System.out.println("适配完成,输出的电压为=" + dst); } return dst; } }

1.3 接口适配器

这种模式看起来就比较霸气了,你不是要用吗?我就把你需要用到的所有方式全部准备好,你去选择一种就好

package com.atguigu.adapter.interfaceadapter;

public interface Interface4 {
    public void output5v();
    public void output10v();
    public void output20v();
    public void output220v();
}

然后再去调用。不想用的方法全部,空实现

 

1.4在SpringMVC中的使用

技术图片

 

对应的页面请求,就来调用对应的控制器再去使用相应的适配器,就像相关的包装然后操作。

 

2 桥接模式

手机问题

技术图片

 

 

 这样会造成类爆炸的问题,而且很不容易扩展,于是我们引入了桥接模式

 

技术图片

 

把功能和样式分开,看一眼主要代码。

package com.atguigu.bridge;

//接口
public interface Brand {
    void open();
    void close();
    void call();
}
package com.atguigu.bridge;

public abstract class Phone {
    
    //组合品牌
    private Brand brand;

    //构造器
    public Phone(Brand brand) {
        super();
        this.brand = brand;
    }
    
    protected void open() {
        this.brand.open();
    }
    protected void close() {
        brand.close();
    }
    protected void call() {
        brand.call();
    }
    
}

这就是桥接模式,简单吧

桥接模式在JDBC中的使用

技术图片

 

 

 3装饰者模式

定制咖啡问题:根据客人订购的商品去定制类,会造成类爆炸问题

第一种方式

 

 

 技术图片

 

第二种方式

 

 技术图片

 

 

 调料内置。

但是这样非常不适合项目的维护,改进难度大不符合ocp原则。

于是我们引入了装饰者模式

技术图片

 

 

 这是主要的喝咖啡类,一下的所有咖啡和配料都会继承

package com.atguigu.decorator;

public abstract class Drink {

    public String des; // 描述
    private float price = 0.0f;
    public String getDes() {
        return des;
    }
    public void setDes(String des) {
        this.des = des;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    
    //计算费用的抽象方法
    //子类来实现
    public abstract float cost();
    
}

这是咖啡类,具体的子类在构造器中初始化价格和描述就好了这里就不写了

package com.atguigu.decorator.coffce;

import com.atguigu.decorator.Drink;

public class Coffee  extends Drink {

    @Override
    public float cost() {
        // TODO Auto-generated method stub
        return super.getPrice();
    }

    
}

在原本咖啡的基础上拼接配料信息就可以了

package com.atguigu.decorator.Decorator;

import com.atguigu.decorator.Drink;

public class Decorator extends Drink {
    private Drink obj;
    
    public Decorator(Drink obj) { //???
        // TODO Auto-generated constructor stub
        this.obj = obj;
    }
    
    @Override
    public float cost() {
        // TODO Auto-generated method stub
        // getPrice ??????
        return super.getPrice() + obj.cost();
    }
    
    @Override
    public String getDes() {
        // TODO Auto-generated method stub
        // obj.getDes() ??????????????
        return des + " " + getPrice() + " && " + obj.getDes();
    }
    
    

}

然后在主类中进行加载就可以了

Drink order = new LongBlack();
System.out.println(
"费用1=" + order.cost()); System.out.println("描述=" + order.getDes()); // 2. order 加入一份牛奶 order = new Milk(order); System.out.println("order 加入一份牛奶 费用 =" + order.cost()); System.out.println("order 加入一份牛奶 描述 = " + order.getDes());

这是运行结果

技术图片

 

 

 装饰者模式在JDK--io流中的使用

技术图片

4组合模式

这是一个层级关系,组合模式就是把这种关系封装为树形结构,而不是继承关系

技术图片

 

 

 

 就是下图:

技术图片

 

将下一层的类存储在集合之中

 

 技术图片

 

 

 组合模式在JDK-- HashMap中的使用

技术图片

 

 

 5外观模式

 影院为例:我们主类操作过多,不适合我们需要一个外观类来处理相应的操作

技术图片

 

这样主类就可以只用调用外观就可以了

 

 技术图片

 

 

 外观类进行分部就行拆解:主类对该类进行操作即可

 

技术图片

 

 

 外观模式在MyBatis中Configuration创建MetaObject的使用

技术图片

 

 

 

 

6享元模式

针对对于可能会反复调用的组件,我们可以使用“池”的概念封装起来

比如:同一份广告对于不同网站的调用共用一份即可

 

 

技术图片

 

 

 用户类:

package com.atguigu.flyweight;

public class User {
    
    private String name;

    
    public User(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    
}

网站类:

package com.atguigu.flyweight;

//具体网站
public class ConcreteWebSite extends WebSite {

    //共享的部分,内部状态
    private String type = ""; //网站发布的形式(类型)

    
    //构造器
    public ConcreteWebSite(String type) {
        
        this.type = type;
    }


    @Override
    public void use(User user) {
        // TODO Auto-generated method stub
        System.out.println("网站的发布形式为:" + type + " 在使用中 .. 使用者是" + user.getName());
    }
    
    
}

创建类:

package com.atguigu.flyweight;

import java.util.HashMap;

// 网站工厂类,根据需要返回压一个网站
public class WebSiteFactory {

    
    //集合, 充当池的作用
    private HashMap<String, ConcreteWebSite> pool = new HashMap<>();
    
    //根据网站的类型,返回一个网站, 如果没有就创建一个网站,并放入到池中,并返回
    public WebSite getWebSiteCategory(String type) {
        if(!pool.containsKey(type)) {
            //就创建一个网站,并放入到池中
            pool.put(type, new ConcreteWebSite(type));
        }
        
        return (WebSite)pool.get(type);
    }
    
    //获取网站分类的总数 (池中有多少个网站类型)
    public int getWebSiteCount() {
        return pool.size();
    }
}

在这个里面每次客户调用的就是同一个类。

在JDK--Integer中的使用

 

 技术图片

 

 7 代理模式

一些功能的使用并不使用类直接使用,而是使用代理类来完成。

7.1静态代理

技术图片

 

 优点:在不修改目标对象的功能前提下进行扩展

缺点:代理类和目标对象实现相同的接口,所以很多代理类一旦接口的方法增加,目标对象和代理对象都要进行修改

7.2动态代理

 

 技术图片

 

public Object getProxyInstance() {
        
        //说明
        /*
         *  public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
                                          
            //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
            //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
            //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(), 
                new InvocationHandler() {
                    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // TODO Auto-generated method stub
                        System.out.println("JDK代理开始~~");
                        //反射机制调用目标对象的方法
                        Object returnVal = method.invoke(target, args);
                        System.out.println("JDK代理提交");
                        return returnVal;
                    }
                }); 
    }

主要依赖于早就写好了的Proxy代理类中的newProxyInstance 通过反射机制进行 动态代理

7.3Cglib代理

也叫子类代理,在没有接口的时候,就是用目标对象的子类进行代理。(ps:使用的时候需要导包)

技术图片

 

 

package com.atguigu.proxy.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ProxyFactory implements MethodInterceptor {

    //维护一个目标对象
    private Object target;
    
    //构造器,传入一个被代理的对象
    public ProxyFactory(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();
        
    }
    

    //重写  intercept 方法,会调用目标对象的方法
    @Override
    public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("Cglib代理模式 ~~ 开始");
        Object returnVal = method.invoke(target, args);
        System.out.println("Cglib代理模式 ~~ 提交");
        return returnVal;
    }

}

说实话对于这个代理我还没有怎么弄懂

在防火墙代理,缓存代理,远程代理和同步代理中有广泛应用

 

以上就是七种结构性设计模式。

 





以上是关于设计模式 ---- 七种结构性型设计模式的主要内容,如果未能解决你的问题,请参考以下文章

超详细-七种常见结构型模式的描述总结与代码分析

23种状态模式的理解

设计模式的理解

设计模式入门

设计模式---创建型模式

设计模式之结构型模式