设计模式 ---- 七种结构性型设计模式
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; } }
说实话对于这个代理我还没有怎么弄懂
在防火墙代理,缓存代理,远程代理和同步代理中有广泛应用
以上就是七种结构性设计模式。
以上是关于设计模式 ---- 七种结构性型设计模式的主要内容,如果未能解决你的问题,请参考以下文章