目录

5.代理模式

6.桥接模式

7.装饰器模式

8.适配器模式

9.门面模式

10.组合模式

11.享元模式


主要解决“类或对象的组合或组装”问题,将不同功能代码解耦

5.代理模式

在不直接修改原有类的前提下对原有类的方法功能进行扩展。

通过引入代理类(构参带入)来给原始类附加功能

示例:

定义一个绘制api DrawApi, 需要在绘制前后进行一些扩展功能(打点,监控等)

1.静态代理

缺点:
1:如果原始类有多个方法,我们需要在代理类中,将原始类中的所有的方法,都重新实现一遍
2:如果存在多个被代理类(比如下面的绘制 和 测算两个类) 都需要通过代理模式添加特殊功能,
则需要针对每个被代理类都创建一个代理类

//定义一个绘制接口(原始类)interface DrawApi {void draw();void refresh();}//定义具体的圆形绘制方案,被代理类static class CircleDraw implements DrawApi {@Overridepublic void draw() {System.out.println("画一个圆");}@Overridepublic void refresh() {System.out.println("刷新");}}//定义一个测算接口,原始类interface CalculateApi {void calculate();}//定义一个绘制代理类,代理实现具体的绘制功能,代理类static class DrawProxy implements DrawApi {//被代理的绘制方案private DrawApi target;//构造器public DrawProxy() {this.target = new CircleDraw();}@Overridepublic void draw() {before();target.draw();after();}@Overridepublic void refresh() {//缺点:我们需要在代理类中,将原始类中的所有的方法,都重新实现一遍}private void after() {System.out.println("执行后 做一些事情");}private void before() {System.out.println("执行前 做一些事情");}}public static void main(String[] args) {//使用静态代理new DrawProxy().draw();// 如果需要扩展其他原始类,则这样行不通//new DrawProxy(new CalculateApi()).draw();//线程也用到了代理模式,传入不同的runnable实现//new Thread(实现runnable接口的实例化对象).start();}

2.动态代理

主要是为了解决静态代理的两个缺点

//定义一个绘制接口,原始类interface DrawApi {void draw();void refresh();}//定义具体的圆形绘制方案,被代理类static class CircleDraw implements DrawApi {@Overridepublic void draw() {System.out.println("画一个圆");}@Overridepublic void refresh() {System.out.println("刷新");}}//定义一个测算接口,原始类interface CalculateApi {void calculate();}//定义圆形的测算方案,被代理类static class CircleCalculate implements CalculateApi {@Overridepublic void calculate() {System.out.println("测量圆的尺寸");}}//动态代理实现类//优点:不需要将将原始类中的所有的方法,都重新实现一遍public static class DrawProxy {public DrawProxy() {}public Object createProxy(Object proxiedObject) {Class<?>[] interfaces = proxiedObject.getClass().getInterfaces();DynamicProxyHandler handler = new DynamicProxyHandler(proxiedObject);return Proxy.newProxyInstance(proxiedObject.getClass().getClassLoader(), interfaces, handler);}//代理类的实现处理接口private class DynamicProxyHandler implements InvocationHandler {private final Object drawImpl;public DynamicProxyHandler(Object drawImpl) {this.drawImpl = drawImpl;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object result = method.invoke(drawImpl, args);String apiName = drawImpl.getClass().getName() + ":" + method.getName();System.out.println("执行方法:" + apiName);after();return result;}private void after() {System.out.println("执行后 做一些事情");}private void before() {System.out.println("执行前 做一些事情");}}}public static void main(String[] args) {DrawProxy proxy = new DrawProxy();DrawApi drawApi = (DrawApi) proxy.createProxy(new CircleDraw());drawApi.draw();//完美解决 原始类有多个的问题CalculateApi calculateApi = (CalculateApi) proxy.createProxy(new CircleCalculate());calculateApi.calculate();}

6.桥接模式

概念:
与代理模式容易混淆。一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。
通俗的说,就是一个类如果有多个属性需要变化,在进行扩展(继承)时会导致新增的子类指数增加,所以需要通过桥接模式将继承改为组合的方式,
将属性的维度解藕出来,将抽象与原本复杂的实现分离,提高扩展能力。

区别:
与代理模式相比,假设将一个纬度抽象以后,执行的方法命名为a()
代理模式侧重于 通过代理的方式扩展被代理类的功能
桥接模式侧重于 通过组合的方式让不同的纬度的原始类可以搭配使用

示例:
以Android画图举例,需要提供一个接口DrawApi,可以绘制三种颜色,与三种形状,普通的做法是通过子类实现不同的组合,一共有9种子类。
这里把颜色解藕然后通过构参带入,把形状解藕为通过子类实现,使其变为两个自由的纬度,通过组合关系(也就是桥梁)任意组合在一起,
可以大幅减少实现的类型。

//颜色抽象化,原始类interface Color {String getColor();}//具体的红色,原始类实现static class RedColor implements Color {@Overridepublic String getColor() {return "红色";}}//创建桥接的实现接口。画图apistatic abstract class DrawApi {protected Color mColor;public DrawApi(final Color color) {mColor = color;}abstract void draw();}//桥接模式实现类static class CircleDraw extends DrawApi {public CircleDraw(final Color color) {super(color);}@Overridevoid draw() {System.out.println("画一个 " + mColor.getColor() + " 的圆形");}}public static void main(String[] args) {DrawApi drawApi = new CircleDraw(new RedColor());drawApi.draw();}

7.装饰器模式

概念:
装饰器模式是指给一个类增强一些方法,对其做一些包装,但是不会影响改变原本类。

异同:
1.与代理模式的区别
装饰器模式看起来跟代理模式特别的相似,但是
对于代理模式来说可以作出一些操作改变原有代码,也就是说带有侵入性。
装饰者模式侧重于添加添加额外的功能职责,也可以重叠使用。
2.与继承的区别:
继承设计子类,是在编译时静态决定的,通过组合的做法扩展对象,可以在运行时动态地进行扩展
装饰者模式通过组合和委托,可以在运行时动态地为对象加上新的行为

示例:
需要一个画图api,在draw之后,需要设置颜色和形状

//画图api抽象类static abstract class DrawComponent {abstract void draw();}static class DrawApi extends DrawComponent {@Overridevoid draw() {System.out.println("画图");}}/*** Decorator,装饰抽象类,继承了Component* 从外类来扩展Component类的功能,但对于Component来说,* 是无需知道Decorator的存在的*/static abstract class DrawDecorator extends DrawComponent {protected DrawComponent component;public DrawComponent getComponent() {return component;}public void setComponent(final DrawComponent component) {this.component = component;}@Overridevoid draw() {if (component != null) {component.draw();}}}static class ShapeDrawDecorator extends DrawDecorator {@Overridevoid draw() {super.draw();System.out.println("设置形状");}}static class ColorDrawDecorator extends DrawDecorator {@Overridevoid draw() {super.draw();System.out.println("设置颜色");}}public static void main(String[] args) {DrawApi drawApi = new DrawApi();ShapeDrawDecorator shapeDrawDecorator = new ShapeDrawDecorator();shapeDrawDecorator.setComponent(drawApi);ColorDrawDecorator colorDrawDecorator = new ColorDrawDecorator();colorDrawDecorator.setComponent(shapeDrawDecorator);colorDrawDecorator.draw();}

8.适配器模式

概念:
将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。(比如Android中列表的Adapter)
分为类适配器,对象适配器
IDrawApi为绘图接口,Printer为不兼容IDrawApi的打印器功能类,Adapter通过继承或者组合兼容两种功能

问题:
应该选择类适配器还是对象适配器?
如果Printer接口并不多,那两种实现方式都可以。
如果Printer接口很多,而且Printer和IDrawApi接口定义大部分都相同,那我们推荐使用类适配器,因为Adaptor复用父类Printer的接口,比起对象适配器的实现方式,Adaptor的代码量要少一些。
如果Printer接口很多,而且Printer和IDrawApi接口定义大部分都不相同,那我们推荐使用对象适配器,因为组合结构相对于继承更加灵活。

示例:
类适配器:基于继承实现

/*** 类适配器,基于继承*/interface IDrawApi {void draw();}/*** 打印*/static class Printer {public void print() {System.out.println("打印");}}/*** Adapter既可以绘画也可以打印*/static class Adapter extends Printer implements IDrawApi {@Overridepublic void draw() {System.out.println("绘画");}@Overridepublic void print() {super.print();}}public static void main(String[] args) {Adapter adapter = new Adapter();adapter.draw();adapter.print();}

示例:
对象适配器:基于组合实现

/*** 绘图*/interface IDrawApi {void draw();}/*** 打印*/static class Printer {public void print() {System.out.println("打印");}}/*** Adapter既可以绘画也可以打印*/static class Adapter implements IDrawApi {private Printer mPrinter;public Adapter(final Printer printer) {mPrinter = printer;}@Overridepublic void draw() {System.out.println("绘画");}public void print() {mPrinter.print();}}public static void main(String[] args) {Adapter adapter = new Adapter(new Printer());adapter.draw();adapter.print();}

9.门面模式

概念:
也叫外观模式,为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。
简单来说,就是将多个接口调用替换为一个门面接口调用。

static class TextHelper {public void print() {System.out.println("写字");}}static class DrawHelper {public void print() {System.out.println("画图");}}static class PrinterManager {TextHelper mTextHelper;DrawHelper mDrawHelper;public PrinterManager(final TextHelper textHelper, final DrawHelper drawHelper) {mTextHelper = textHelper;mDrawHelper = drawHelper;}public void print() {if (mTextHelper != null) {mTextHelper.print();}if (mDrawHelper != null) {mDrawHelper.print();}}}public static void main(String[] args) {PrinterManager printerManager = new PrinterManager(new TextHelper(), new DrawHelper());printerManager.print();}

10.组合模式

概念:
将一组对象组织(Compose)成树形结构,以表示一种“部分-整体”的层次结构。
组合让客户端(在很多设计模式书籍中,“客户端”代指代码的使用者。)可以统一单个对象和组合对象的处理逻辑。

示例:
希望在内存中构建整个公司的人员架构图(部门、子部门、员工的隶属关系),
并且提供接口计算出部门的薪资成本(隶属于这个部门的所有员工的薪资和)。
采用组合的方式可以更方便的处理员工与部门的工资计算。

//人力资源static abstract class HumanResource {protected long id;protected double salary;public HumanResource(long id) {this.id = id;}public long getId() {return id;}public abstract double calculateSalary();}//员工static class Employee extends HumanResource {public Employee(long id, double salary) {super(id);this.salary = salary;}@Overridepublic double calculateSalary() {return salary;}}//部门public static class Department extends HumanResource {private List<HumanResource> subNodes = new ArrayList<>();public Department(long id) {super(id);}@Overridepublic double calculateSalary() {double totalSalary = 0;for (HumanResource hr : subNodes) {totalSalary += hr.calculateSalary();}this.salary = totalSalary;return totalSalary;}public void addSubNode(HumanResource hr) {subNodes.add(hr);}}public static void main(String[] args) {//it部门Department itDepartment = new Department(1);itDepartment.addSubNode(new Employee(1, 5000));itDepartment.addSubNode(new Employee(2, 5100));itDepartment.addSubNode(new Employee(3, 5200));itDepartment.addSubNode(new Employee(4, 5300));itDepartment.addSubNode(new Employee(5, 5400));//客户部门Department customerDepartment = new Department(1);customerDepartment.addSubNode(new Employee(1, 1000));customerDepartment.addSubNode(new Employee(2, 1100));customerDepartment.addSubNode(new Employee(3, 1200));customerDepartment.addSubNode(new Employee(4, 1300));customerDepartment.addSubNode(new Employee(5, 1400));//总薪水double salaryAll = itDepartment.calculateSalary() + customerDepartment.calculateSalary();System.out.println("总薪水:" + salaryAll);}

11.享元模式

概念:
当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,
我们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用

示例:
直播间需要实现弹幕表情功能,每一个弹幕的id和表情是固定的,但是x,y坐标不同。

// 享元类,弹幕static class BarrageUnit {public int id;private String face;public BarrageUnit(final int id, final String face) {this.id = id;this.face = face;}@Overridepublic String toString() {return "BarrageUnit{" +"id=" + id +", face='" + face + '\'' +'}';}}//弹幕类static class Barrage {public BarrageUnit mBarrageUnit;public float x, y;public Barrage(final BarrageUnit barrageUnit, final float x, final float y) {mBarrageUnit = barrageUnit;this.x = x;this.y = y;}@Overridepublic String toString() {return "Barrage{" +"mBarrageUnit=" + mBarrageUnit +", x=" + x +", y=" + y +'}';}}static class ChessPieceUnitFactory {private static final Map<Integer, BarrageUnit> barrages = new HashMap<>();static {barrages.put(1, new BarrageUnit(1, "微笑"));barrages.put(2, new BarrageUnit(2, "愤怒"));barrages.put(3, new BarrageUnit(3, "狗头"));//...省略初始化其他弹幕的代码...}public static BarrageUnit getChessPiece(int barrageId) {return barrages.get(barrageId);}}static class LiveRoom {private final Map<Integer, Barrage> barrages = new HashMap<>();//展示表情弹幕public void showFace(int barrageId, int toPositionX, int toPositionY) {barrages.put(barrageId, new Barrage(ChessPieceUnitFactory.getChessPiece(barrageId), toPositionX, toPositionX));}public void draw() {System.out.println("绘制弹幕:" + barrages.toString());}}public static void main(String[] args) {LiveRoom liveRoom = new LiveRoom();liveRoom.showFace(1,100,100);liveRoom.showFace(2,200,200);liveRoom.showFace(3,300,300);liveRoom.draw();}

23种设计模式归纳总结——结构型相关推荐

  1. 23种设计模式之我见----结构型设计模式(2)

    在软件工程中,创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象.基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度.创建型模式通过以某种方式控制对象的创建来解决问题 ...

  2. 备战面试日记(3.3) - (设计模式.23种设计模式之结构型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.9 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  3. 详解23种设计模式(基于Java)—— 结构型模式(三 / 五)

    目录 3.结构型模式(7种) 3.1.代理模式 3.1.1.概述 3.1.2.结构 3.1.3.静态代理 3.1.4.JDK动态代理 3.1.5.CGLIB动态代理 3.1.6.三种代理的对比 3.1 ...

  4. 23种设计模式——结构型设计模式(7种)

    目录 ☞ 23 种设计模式--创建型设计模式(5种) ☞ 23 种设计模式--结构型设计模式(7种) ☞ 23 种设计模式--行为型设计模式(11种) 3. 结构型设计模式 结构型模式描述如何将类或对 ...

  5. Java开发中的23种设计模式详解(转)

    设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  6. 【设计模式】Java 23种设计模式对比总结

    一.设计模式的分类 创建型模式,共五种(1-5):工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种(6-12):适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组 ...

  7. 【java】java开发中的23种设计模式详解

    设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  8. java 23种设计模式及具体例子 收藏有时间慢慢看

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...

  9. java 23种设计模式(转载)

    设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  10. Python之23种设计模式

    目录篇: python相关目录篇 点击跳转 目录 设计模式介绍 GoF该书设计了23个设计模式 设计模式(Design Patterns)--可复用面向对象软件的基础 设计模式分类 1 创建型模式 2 ...

最新文章

  1. FreeBSD 6.0架设管理与应用-第三章 UNIX 系统入门
  2. 8个我希望早点意识到的学生思维
  3. Java后端架构开荒实战(二)——单机到集群
  4. python怎样导入excel数据_python导入excel数据
  5. 没有外层实列可以访问_这糕点外层香酥,内馅香甜可口,让人吃一次就爱上了,做起来...
  6. Error:The supplied javaHome seems to be invalid. I cannot find the java executable
  7. 配置MaxCompute任务消费监控告警,避免资源过度消费
  8. UVa 10066 - The Twin Towers(LCS水题)
  9. nyoj--860--又见01背包--01背包的变形
  10. 学术论文海报模板_推荐 | 绘制学术论文中的图表一般有哪些专业的软件?
  11. 图的常见衡量指标及算法调研
  12. 哪款蓝牙耳机戴着舒服?佩戴舒适度高的四款蓝牙耳机推荐
  13. Java自定义模板设计
  14. 【机器学习】之 主成分分析PCA
  15. RPC VS REST
  16. win7无线网络图标出现红叉原因
  17. java程序占用cpu100%问题查找方案
  18. ArcMap如何打开.adf图层文件并将其文件转换为shp文件
  19. (五十三) Android O wifi 状态机消息处理及状态切换流程分析-以WifiController为例
  20. 星空联盟全面采用AWS以开创航空旅行新时代

热门文章

  1. 群赛14----2017.9.24
  2. 好莱坞电影调色_好莱坞正式支持电影制作中的开源
  3. JVM 运行机制及其原理
  4. PostgreSQL表增加一列或删除一列
  5. 算法刷题记录(Day 73)
  6. 数据从hana倒回Oracle的方法,SAP HANA SLT 将Oracle表 数据同步到HANA数据库
  7. SLT 定义vetctor对象,vector构造函数
  8. Flink链接kafka并解析Json文件(三)
  9. 计算机主机进水无法启动,电脑主机进水会有什么影响!
  10. 大数据云计算支撑公安工作跨越发展