• 软件设计模式(二):工厂、门面、调停者和装饰器模式


    前言

            在这篇文章中,荔枝将会梳理软件设计模式中的四种:工厂模式、Facade模式、Mediator模式和装饰器Decorator模式。其中比较重要的就是工厂模式和装饰器模式,工厂模式在开发中使用的频数比较高。希望荔枝的这篇文章能讲清楚哈哈哈哈,希望能帮助到有需要的小伙伴~~~


    文章目录

    前言

    一、工厂模式

    1.1 简单工厂

    1.2 工厂方法

    1.3 抽象工厂

    二、调停者模式和门面模式

    2.1 门面模式Facade

    2.2 调停者模式Mediator

    三、装饰器模式Decorator 

    总结


    一、工厂模式

    1.1 简单工厂

    首先定义一个交通工具的工厂函数接口Moveable。

    1. package com.crj.factorymethod;
    2. /**
    3. * 工厂函数接口
    4. */
    5. public interface Moveable {
    6. void go();
    7. }

     我们要实现某一种方式的交通工具就需要通过将该交通工具类实现该接口并重写go方法。

    1. package com.crj.factorymethod;
    2. /**
    3. * Car类继承工厂函数接口
    4. */
    5. public class Car implements Moveable {
    6. public void go() {
    7. System.out.println("Car go wuwuwuwuw....");
    8. }
    9. }

    通过简单工厂模式来返回实例化后的交通工具对象。

    1. package com.crj.factorymethod;
    2. /**
    3. * 简单工厂模式
    4. * 简单工厂的可扩展性不好
    5. */
    6. public class SimpleVehicleFactory {
    7. public Car createCar() {
    8. //before processing
    9. return new Car();
    10. }
    11. public Broom createBroom() {
    12. return new Broom();
    13. }
    14. }

    1.2 工厂方法

            上文中可以看出,简单工厂模式的可扩展性比较差,但我们需要新创建一种交通方式的时候就需要重新在工厂SimpleVehicleFactory定义并写死相应的对象方法,这在后期的时候并不容易维护。那么还可以通过不同交通工具各自有一个工厂,方法类型都是继承自Moveable,返回值也是Moveable类型。

    1. package com.crj.factorymethod;
    2. /**
    3. * 工厂方法
    4. */
    5. public class CarFactory {
    6. public Moveable create() {
    7. System.out.println("a car created!");
    8. return new Car();
    9. }
    10. }

    main方法

    1. package com.crj.factorymethod;
    2. public class Main {
    3. public static void main(String[] args) {
    4. Moveable m = new CarFactory().create();
    5. m.go();
    6. }
    7. }

    1.3 抽象工厂

    前面我们已经把产品的构建和工厂一一对应了,但是我们操作起产品簇还不是很方便,我们可以通过抽象工厂直接操作创建一整个产品簇。在实现创建产品簇之前,我们需要创建抽象产品类、抽象工厂、具体产品类和具体的工厂。

    抽象产品类

    首先定义一些抽象产品类,并定义相应的抽象方法。

    抽象工厂AbstractFactory

    抽象工厂定义抽象的方法用于创建相应的产品簇中的类型产品。 

    1. package com.mashibing.dp.abstractfactory;
    2. public abstract class AbastractFactory {
    3. abstract Food createFood();
    4. abstract Vehicle createVehicle();
    5. abstract Weapon createWeapon();
    6. }

    具体工厂类

    具体工厂类继承自抽象工厂类,并重写不同类型的产品创建产品的方法。 

    具体产品类

    具体的产品类继承自抽象产品类

    main文件

            在main文件中我们通过实例化具体产品类得到对象并调用相应的产品创建方法首先产品簇的创建。可以看到在这段demo中我们即使需要得到不同的产品簇,也仅需要通过实例化不同的工厂类即可。

    1. package com.mashibing.dp.abstractfactory;
    2. public class Main {
    3. public static void main(String[] args) {
    4. AbastractFactory f = new ModernFactory();
    5. Vehicle c = f.createVehicle();
    6. c.go();
    7. Weapon w = f.createWeapon();
    8. w.shoot();
    9. Food b = f.createFood();
    10. b.printName();
    11. }
    12. }

    具体的逻辑可以看一下这张图,荔枝感觉还是没讲得很清楚,剩下三分自己就得靠大家聪明得脑瓜啦。


    二、调停者模式和门面模式

    2.1 门面模式Facade

            门面模式要求一个系统外部与其内部的通信必须通过一个统一的对象进行,通过一个高层次的接口管理外部通信与内部对象簇之间的通信,简单理解就是一个中介(门面),外部仅需要跟这个中介对接即可,中介再委派客户端发送的请求到相应的子系统中,这也是一种黑箱操作。在该模式下可以同时拥有一个或者多个系统,每个系统是一个类的集合,同时系统对于门面只是当成客户端来处理。

    需要注意的是:

    • 一个系统可以有多个门面

    • 门面不参与系统内的业务逻辑

    2.2 调停者模式Mediator

            调停者模式相当于一个星型连接,该模式多用于消息中间件如MQ中,对象间只需要跟中间人进行沟通即可,由中间人进行消息的收发和处理,是一种解耦的操作。对于门面模式和调停者模式的区别详情可以下图,二者其实区别并不大并且在某些场景下是可以互换的。


    三、装饰器模式Decorator 

    装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些功能的模式,它属于对象结构型模式。

    优点:

    • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
    • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
    • 装饰器模式完全遵守开闭原则

    缺点:装饰器模式会增加许多子类,过度使用会增加程序复杂性。

    大致看了一些概念性的东西大机器是不是感觉不是特别具象,下面我们可以通过一个例子来理解一下装饰器模式具体是一个怎样的软件设计模式。 

    1. package com.crj.Decorator;
    2. public class Decorator {
    3. /**
    4. * 装饰器模式
    5. * 使用实体装饰类装饰
    6. * @param args
    7. */
    8. public static void main(String[] args) {
    9. A a = new A();
    10. B b = new B();
    11. RedShapeDecorator rda = new RedShapeDecorator(a);
    12. rda.draw();
    13. BlueShapeDecorator rdb = new BlueShapeDecorator(b);
    14. rdb.draw();
    15. }
    16. }
    17. /**
    18. * 接口
    19. */
    20. interface Shape{
    21. void draw();
    22. }
    23. /**
    24. * 接口实现类
    25. */
    26. class A implements Shape{
    27. @Override
    28. public void draw() {
    29. System.out.println("这是A类");
    30. }
    31. }
    32. class B implements Shape{
    33. @Override
    34. public void draw() {
    35. System.out.println("这是B类");
    36. }
    37. }
    38. /**
    39. * 抽象装饰类
    40. */
    41. abstract class ShapeDecorator implements Shape{
    42. protected Shape decoratedShape;
    43. public ShapeDecorator(Shape decoratedShape) {
    44. this.decoratedShape = decoratedShape;
    45. }
    46. @Override
    47. public void draw() {
    48. decoratedShape.draw();
    49. }
    50. }
    51. /**
    52. * 第一个实体装饰类
    53. */
    54. class RedShapeDecorator extends ShapeDecorator{
    55. public RedShapeDecorator(Shape decoratedShape) {
    56. super(decoratedShape);
    57. }
    58. @Override
    59. public void draw() {
    60. super.draw();
    61. setRedShapeDecorator(decoratedShape);
    62. }
    63. private void setRedShapeDecorator(Shape decoratedShape){
    64. System.out.println("Red");
    65. }
    66. }
    67. /**
    68. * 第二个实体装饰类
    69. */
    70. class BlueShapeDecorator extends ShapeDecorator{
    71. public BlueShapeDecorator(Shape decoratedShape) {
    72. super(decoratedShape);
    73. }
    74. @Override
    75. public void draw() {
    76. super.draw();
    77. setRedShapeDecorator(decoratedShape);
    78. }
    79. private void setRedShapeDecorator(Shape decoratedShape){
    80. System.out.println("Blue");
    81. }
    82. }

            在上面的demo中,我们定义了一个普通接口、两个基本的接口实现类、一个抽象装饰类和两个实体装饰类。接口实现类和抽象装饰类都实现了接口的实现方法并重写接口的方法。实体装饰类继承自抽象装饰类,由于抽象装饰类中含有有参构造方法,因此需要使用super关键字声明继承对象。我们通过往实体装饰类对象中传入一个实体类对象,实现了对对象调用的draw()方法的装饰。

            可以看一下这张图,我们可以发现其实在Shape接口上我们定义了一个ShapeDecorator抽象装饰类来装饰,所谓装饰其实也是增加功能。在前面中我们也提及装饰的本质就是使用抽象类继承接口,再使用具体的实现类装饰上功能,这种方式极好的解决了子类爆炸的问题。


    总结

            到现在荔枝也梳理了几种设计模式了,总结一下自己的学习方法:主要是根据文档和大佬视频资源讲解梳理的,再自己手敲示例实现一遍,收获和体会确实是挺大的。学习设计模式可能会比较枯燥,大家加油,荔枝要继续前行咯~

    今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

  • 相关阅读:
    大数据可视化之医疗大数据平台
    树莓派更换国内可用镜像源
    Unity3D 框架如何搭建基于纯Lua的U框架与开发模式详解
    2022-08-26
    图解辗转相除法求解最大公约数
    09—DOM和BOM
    网络——IPv6(一)
    深入理解JavaScript事件循环机制
    VP Atcoder Beginner Contest 265
    【C++系列P3】‘类与对象‘-三部曲——[基础知识](1/3)
  • 原文地址:https://blog.csdn.net/qq_62706049/article/details/132710160