23种设计模式之外观模式、组合模式、享元模式

23种设计模式之外观模式、组合模式、享元模式

首页休闲益智图形工厂更新时间:2024-05-11
前言

本章节给您介绍23种设计模式的结构型模式中剩余的3种设计模式,分别为:`外观模式`、`组合模式`和`享元模式`。

如有帮助记得点赞哦,有疑问或者建议欢迎评论区留言!

一、外观模式

在现实生活中,常常存在办事较复杂的例子,如办房产证或注册一家公司,有时要同多个部门联系,这时要是有一个综合部门能解决一切手续问题就好了。

软件设计也是这样,当一个系统的功能越来越强,子系统会越来越多,客户对系统的访问也变得越来越复杂。这时如果系统内部发生改变,客户端也要跟着改变,这违背了“开闭原则”,也违背了“迪米特法则”,所以有必要为多个子系统提供一个统一的接口,从而降低系统的耦合度,这就是外观模式的目标。

`外观(Facade)模式又叫作门面模式`,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

1.1、实现方式1.1.1、外观模式角色1.1.2、代码实现

通过智能家居案例实现:家中有电视、空调、电灯等家电,当我们说打开时,所有家电都打开,说关闭时所有家电都关闭。

其实就是通过一个操作入口,内部聚合了一系列的操作,不妨想一想智能语音助手。

// 灯类 public class Light { public void on() { System.out.println("打开灯。。。。。。"); } public void off() { System.out.println("关闭灯。。。。。。"); } } // 电视类 public class TV { public void on() { System.out.println("打开电视。。。。。。"); } public void off() { System.out.println("关闭电视。。。。。。"); } } // 空调类 public class AirCondition { public void on() { System.out.println("打开空调。。。。。。"); } public void off() { System.out.println("关闭空调。。。。。。"); } } // 门面类 public class SmartAppliancesFacade { // 聚合 private Light light; private TV tv; private AirCondition airCondition; public SmartAppliancesFacade() { this.light = new Light(); this.tv = new TV(); this.airCondition = new AirCondition(); } public void say(String msg) { if("打开".equals(msg)) { on(); }else if("关闭".equals(msg)) { off(); }else { System.out.println("我还听不懂你在说什么"); } } private void on() { light.on();; tv.on(); airCondition.on(); } private void off() { light.off(); tv.off(); airCondition.off(); } } // 客户端类 public class Client { public static void main(String[] args) { SmartAppliancesFacade facade = new SmartAppliancesFacade(); facade.say("打开"); System.out.println("===睡觉==="); facade.say("关闭"); } }1.2、外观模式优缺点

优点

缺点

1.3、应用场景二、组合模式

在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣服与衣柜、以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,如果用组合模式来实现会很方便。

组合(Composite Pattern)模式的定义:有时又叫作`整体-部分(Part-Whole)模式`,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。

2.1、实现方式2.1.1、组合模式角色2.1.2、代码实现

通过一个 管理系统 左侧菜单栏的案例实现

// 组件菜单:属于抽象根节点 public abstract class MenuComponent { // 菜单组件名称 protected String name; // 菜单组件层级 protected int level; // 添加子菜单 public void add(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } // 移除子菜单 public void remove(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } // 获取指定的子菜单 public MenuComponent getChild(int index) { throw new UnsupportedOperationException(); } // 获取菜单或菜单项的名称 public String getName() { return name; } // 打印菜单名称的方法(包含子菜单和子菜单项) public abstract void print(); } // 菜单类:属于树枝节点 public class Menu extends MenuComponent{ // 菜单可以有子菜单 private List<MenuComponent> menuComponentList = new ArrayList<>(); public Menu(String name,int level) { this.name = name; this.level = level; } @Override public void add(MenuComponent menuComponent) { menuComponentList.add(menuComponent); } @Override public void remove(MenuComponent menuComponent) { menuComponentList.remove(menuComponent); } @Override public MenuComponent getChild(int index) { return menuComponentList.get(index); } @Override public void print() { for (int i = 0; i < level; i ) { System.out.print("--"); } // 打印本菜单名称 System.out.println(name); // 打印子菜单名 for (MenuComponent menuComponent : menuComponentList) { menuComponent.print(); } } } // 菜单项类 public class MenuItem extends MenuComponent{ public MenuItem(String name,int level) { this.name = name; this.level = level; } @Override public void print() { for (int i = 0; i < level; i ) { System.out.print("--"); } // 打印名称 System.out.println(name); } } // 创建对应的菜单,指定层级,并添加菜单项 public class Client { public static void main(String[] args) { MenuComponent menu1 = new Menu("菜单管理", 2); menu1.add(new MenuItem("页面访问",3)); menu1.add(new MenuItem("展开菜单",3)); menu1.add(new MenuItem("编辑菜单",3)); menu1.add(new MenuItem("删除菜单",3)); menu1.add(new MenuItem("新增菜单",3)); MenuComponent menu2 = new Menu("权限管理", 2); menu2.add(new MenuItem("页面访问",3)); menu2.add(new MenuItem("提交保存",3)); MenuComponent menu3 = new Menu("角色管理", 2); menu3.add(new MenuItem("页面访问",3)); menu3.add(new MenuItem("新增角色",3)); menu3.add(new MenuItem("修改角色",3)); // 创建1级菜单 MenuComponent menu = new Menu("系统管理", 1); menu.add(menu1); menu.add(menu2); menu.add(menu3); menu.print(); } }2.2、组合模式优缺点

优点

缺点

2.3、应用场景三、享元模式

在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈。

例如,围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源,这就是享元模式的产生背景。

享元(Flyweight)模式的定义:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。

3.1、实现方式3.1.1、享元模式中角色3.1.2、代码实现

案例:俄罗斯方块中有固定的几种形状。我们可以将这些形状进行共享

// 抽象的形状类 public abstract class AbstractBox { // 获取图形的方法 public abstract String getShape(); // 显示图形颜色 public void display(String color) { System.out.println("方块形状:" getShape() ", 颜色:" color); } } public class IBox extends AbstractBox{ @Override public String getShape() { return "I"; } } public class LBox extends AbstractBox{ @Override public String getShape() { return "L"; } } public class OBox extends AbstractBox{ @Override public String getShape() { return "O"; } } // 图形工厂 public class BoxFactory { // 存储形状 private HashMap<String,AbstractBox> box; // 创建单例的工厂对象 private static BoxFactory boxFactory = new BoxFactory(); public BoxFactory() { this.box = new HashMap<>(); box.put("I",new IBox()); box.put("O",new OBox()); box.put("L",new LBox()); } public static BoxFactory getBoxFactory() { return boxFactory; } public AbstractBox getShape(String type) { return box.get(type); } } public class Client { public static void main(String[] args) { BoxFactory boxFactory = BoxFactory.getBoxFactory(); AbstractBox iShape = boxFactory.getShape("I"); iShape.display("灰色"); AbstractBox iShap2 = boxFactory.getShape("I"); iShap2.display("红色"); System.out.println(iShape == iShap2); } }

上边的案例急事通过一个Map来存储,如果需要什么对象直接从Map中获取即可,获取的都是同一个对象

3.2、享元模式优缺点

优点

缺点

3.2.1、外部状态和内部状态

享元对象共享的关键是区分了`内部状态`(Intrinsic State)和`外部状态`(Extrinsic State)。

`内部状态`:存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享,比如【构造方法的参数】

`外部状态`:享元对象的外部状态通常由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部,比如【 方法参数)】。随环境改变而改变的、不可以共享的状态。一个外部状态与另一个外部状态之间是相互独立的

3.3、享元模式应用场景

当系统中多处需要同一组信息时,可以把这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多出需要使用的地方,避免大量同一对象的多次创建,降低大量内存空间的消耗。

享元模式其实是 `工厂方法模式` 的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法模式生成对象的,只不过享元模式为工厂方法模式增加了缓存这一功能。

享元模式是通过减少内存中对象的数量来节省内存空间的,所以以下几种情形适合采用享元模式。

总结

本章节给您介绍了结构型设计模式中的后三种,至此设计模式中的`创建型` 和 `结构型`设计模式已经介绍完毕。接下来会继续更新最后的 `行为型` 设计模式。敬请期待!

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved