设计模式系列 - 03结构型

适配器模式

  • 模式动机

    将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

  • 类图
    在这里插入图片描述

  • 优缺点

    • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
    • 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
    • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合开闭原则。
  • 案例

    • javax.xml.bind.annotation.adapters.XmlAdapter
    • org.springframework.aop.framework.adapter.AdvisorAdapter
    • org.springframework.orm.jpa.JpaVendorAdapter
    • org.springframework.web.servlet.HandlerAdapter

桥接模式

  • 模式动机

将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

  • 适用场景
    • 抽象与具体实现之间增加更多的灵活性
    • 一个类存在两个(或多个)独立变化的维度,且这两个维度都需要独立进行扩展
    • 不希望使用继承,因为多层继承导致类的个数剧增
  • 类图
    在这里插入图片描述
  public class ImageExample {
          public static void main(String[] args) {
              Image image = new PNGImage();
              ImageImp imageImp = new WindowsImp();
              image.setImageImp(imageImp);
              image.parseFile("小龙女");
          }
      }
      
      //像素矩阵类:辅助类,各种格式的文件最终都被转化为像素矩阵,不同的操作系统提供不同的方式显示像素矩阵
      class Matrix {
          //此处代码省略
      }
      
      //抽象图像类:抽象类
      abstract class Image {
          protected ImageImp imp;
      
          public void setImageImp(ImageImp imp) {
              this.imp = imp;
          }
      
          public abstract void parseFile(String fileName);
      }
      
      //抽象操作系统实现类:实现类接口
      interface ImageImp {
          public void doPaint(Matrix m);  //显示像素矩阵m
      }
      
      //Windows操作系统实现类:具体实现类
      class WindowsImp implements ImageImp {
          public void doPaint(Matrix m) {
              //调用Windows系统的绘制函数绘制像素矩阵
              System.out.print("在Windows操作系统中显示图像:");
          }
      }
      
      //Linux操作系统实现类:具体实现类
      class LinuxImp implements ImageImp {
          public void doPaint(Matrix m) {
              //调用Linux系统的绘制函数绘制像素矩阵
              System.out.print("在Linux操作系统中显示图像:");
          }
      }
      
      //Unix操作系统实现类:具体实现类
      class UnixImp implements ImageImp {
          public void doPaint(Matrix m) {
              //调用Unix系统的绘制函数绘制像素矩阵
              System.out.print("在Unix操作系统中显示图像:");
          }
      }
      
      //JPG格式图像:扩充抽象类
      class JPGImage extends Image {
          public void parseFile(String fileName) {
              //模拟解析JPG文件并获得一个像素矩阵对象m;
              Matrix m = new Matrix();
              imp.doPaint(m);
              System.out.println(fileName + ",格式为JPG。");
          }
      }
      
      //PNG格式图像:扩充抽象类
      class PNGImage extends Image {
          public void parseFile(String fileName) {
              //模拟解析PNG文件并获得一个像素矩阵对象m;
              Matrix m = new Matrix();
              imp.doPaint(m);
              System.out.println(fileName + ",格式为PNG。");
          }
      }
      
      //BMP格式图像:扩充抽象类
      class BMPImage extends Image {
          public void parseFile(String fileName) {
              //模拟解析BMP文件并获得一个像素矩阵对象m;
              Matrix m = new Matrix();
              imp.doPaint(m);
              System.out.println(fileName + ",格式为BMP。");
          }
      }
      
      //GIF格式图像:扩充抽象类
      class GIFImage extends Image {
          public void parseFile(String fileName) {
              //模拟解析GIF文件并获得一个像素矩阵对象m;
              Matrix m = new Matrix();
              imp.doPaint(m);
              System.out.println(fileName + ",格式为GIF。");
          }
      }
  • 优缺点
    优点:

    • 分离抽象部分及其具体实现部分
    • 提高了系统的可扩展性
    • 符合开闭原则
    • 符合合成复用原则

    缺点:

    • 增加了系统的理解和设计难度
    • 需要正确的识别出系统中两个独立变化的维度
  • 案例

    • java.sql.Driver 与java.sql.DriverManager
    • java.util.logging.Formatter 与 java.util.logging.Handler
      在这里插入图片描述

组合模式

  • 模式动机

    组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

  • 适用场景
    • 希望客户端忽略组合对象与单个对象的差异
    • 处理树形结构
  • 类图
    在这里插入图片描述
public class CompExample {
          public static void main(String[] args) {
      
          }
      }
      
      
      //抽象文件类:抽象构件
      abstract class AbstractFile {
          public abstract void add(AbstractFile file);
      
          public abstract void remove(AbstractFile file);
      
          public abstract AbstractFile getChild(int i);
      
          public abstract void killVirus();
      }
      
      //图像文件类:叶子构件
      class ImageFile extends AbstractFile {
          private String name;
      
          public ImageFile(String name) {
              this.name = name;
          }
      
          public void add(AbstractFile file) {
              System.out.println("对不起,不支持该方法!");
          }
      
          public void remove(AbstractFile file) {
              System.out.println("对不起,不支持该方法!");
          }
      
          public AbstractFile getChild(int i) {
              System.out.println("对不起,不支持该方法!");
              return null;
          }
      
          public void killVirus() {
              //模拟杀毒
              System.out.println("----对图像文件'" + name + "'进行杀毒");
          }
      }
      
      //文本文件类:叶子构件
      class TextFile extends AbstractFile {
          private String name;
      
          public TextFile(String name) {
              this.name = name;
          }
      
          public void add(AbstractFile file) {
              System.out.println("对不起,不支持该方法!");
          }
      
          public void remove(AbstractFile file) {
              System.out.println("对不起,不支持该方法!");
          }
      
          public AbstractFile getChild(int i) {
              System.out.println("对不起,不支持该方法!");
              return null;
          }
      
          public void killVirus() {
              //模拟杀毒
              System.out.println("----对文本文件'" + name + "'进行杀毒");
          }
      }
      
      //视频文件类:叶子构件
      class VideoFile extends AbstractFile {
          private String name;
      
          public VideoFile(String name) {
              this.name = name;
          }
      
          public void add(AbstractFile file) {
              System.out.println("对不起,不支持该方法!");
          }
      
          public void remove(AbstractFile file) {
              System.out.println("对不起,不支持该方法!");
          }
      
          public AbstractFile getChild(int i) {
              System.out.println("对不起,不支持该方法!");
              return null;
          }
      
          public void killVirus() {
              //模拟杀毒
              System.out.println("----对视频文件'" + name + "'进行杀毒");
          }
      }
      
      //文件夹类:容器构件
      class Folder extends AbstractFile {
          //定义集合fileList,用于存储AbstractFile类型的成员
          private ArrayList<AbstractFile> fileList = new ArrayList<AbstractFile>();
          private String name;
      
          public Folder(String name) {
              this.name = name;
          }
      
          public void add(AbstractFile file) {
              fileList.add(file);
          }
      
          public void remove(AbstractFile file) {
              fileList.remove(file);
          }
      
          public AbstractFile getChild(int i) {
              return (AbstractFile) fileList.get(i);
          }
      
          public void killVirus() {
              System.out.println("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒
      
              //递归调用成员构件的killVirus()方法
              for (Object obj : fileList) {
                  ((AbstractFile) obj).killVirus();
              }
          }
      }
  • 优缺点
    优点:

    • 清楚的定义分层次的复杂对象,表示对象的全部或部分层次
    • 让客户端忽略了层次的差异,方便对整个层次结构进行控制
    • 简化客户端代码
    • 符合开闭原则

    缺点:

    • 限制类型时较为复杂
    • 设计变得更加抽象
  • 案例

    • Container#add
    • HashMap#putAll
    • ArrayList#addAll
    • mybatis#SqlNode

装饰者模式

  • 模式动机
    . 动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰者模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

  • 适用场景

    • 扩展一个类的功能或者给一个类添加附加职责;
    • 动态的给一个对象添加功能,这些功能可以在动态的撤销;
  • 类图
    在这里插入图片描述

    public class DecoratorExample {
        public static void main(String[] args) {
            Component component, componentSB;//使用抽象构件定义
    
            component = new Window(); //定义具体构件
    
            componentSB = new ScrollBarDecorator(component); //定义装饰后的构件
    
            componentSB.display();
        }
    }
    
    //抽象界面构件类:抽象构件类,为了突出与模式相关的核心代码,
    // 对原有控件代码进行了大量的简化
    abstract class Component {
    
        public abstract void display();
    
    }
    
    
    //窗体类:具体构件类
    class Window extends Component {
    
        public void display() {
    
            System.out.println("显示窗体!");
    
        }
    
    }
    
    
    //文本框类:具体构件类
    class TextBox extends Component {
    
        public void display() {
    
            System.out.println("显示文本框!");
    
        }
    
    }
    
    
    //列表框类:具体构件类
    class ListBox extends Component {
    
        public void display() {
    
            System.out.println("显示列表框!");
    
        }
    
    }
    
    
    //构件装饰类:抽象装饰类
    class ComponentDecorator extends Component {
    
        private Component component; //维持对抽象构件类型对象的引用
    
        public ComponentDecorator(Component component) {//注入抽象构件类型的对象
            this.component = component;
        }
    
    
        public void display() {
            component.display();
        }
    
    }
    
    
    //滚动条装饰类:具体装饰类
    
    class ScrollBarDecorator extends ComponentDecorator {
        public ScrollBarDecorator(Component component) {
            super(component);
        }
    
    
        public void display() {
            this.setScrollBar();
            super.display();
        }
    
    
        public void setScrollBar() {
            System.out.println("为构件增加滚动条!");
        }
    
    }
    
    
    //黑色边框装饰类:具体装饰类
    
    class BlackBorderDecorator extends ComponentDecorator {
        public BlackBorderDecorator(Component component) {
            super(component);
        }
    
    
        public void display() {
            this.setBlackBorder();
            super.display();
        }
    
    
        public void setBlackBorder() {
            System.out.println("为构件增加黑色边框!");
        }
    
    }
    
  • 优缺点
    优点:

    • 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能;
    • 通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同的效果;
    • 符合开闭原则;

    缺点:

    • 会出现更多的代码,更多的类,增加程序的复杂性;
    • 动态装饰时以及多层装饰时会更复杂;
  • 案例

    • java.io
      在这里插入图片描述
    • org.springframework.cache.transaction.TransactionAwareCacheDecorator
      在这里插入图片描述
    • javax.servlet.ServletRequestWrapper

在这里插入图片描述

外观模式

  • 模式动机

为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。外观模式是迪米特法则的一种具体实现,通过引入一个新的外观角色可以降低原有系统的复杂度,同时降低客户类与子系统的耦合度。

  • 适用场景

    • 当子系统越来越复杂,增加外观模式提供简单调用接口;
    • 构建多层系统结构,利用外观对象作为每层的入口,简化层间调用;
  • 类图
    在这里插入图片描述

  • 优缺点
    优点:

    • 简化了调用过程,无需深入了解子系统,防止带来风险;
    • 减少系统以来,松散耦合;
    • 更好的划分访问的层次;
    • 符合迪米特法则即最少知道原则;

    缺点:

    • 增加子系统 扩展子系统行为容易引入风险;
    • 不符合开闭原则(在增加子系统 扩展子系统时);
  • 案例

    • org.springframework.jdbc.support.JdbcUtils
    • org.apache.catalina.connector.RequestFacade/ResponseFacade
    • org.apache.catalina.session.StandardSessionFacade
    • org.apache.catalina.core.ApplicationContextFacade

享元模式

  • 模式动机

    运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

  • 适用场景

    • 常常应用于系统底层的开发,以便解决系统的性能问题;
    • 系统有大量的相似对象,需要缓冲池的场景;
  • 类图

    public class FlyWeightExample {
        public static void main(String[] args) {
    
            IgoChessman black1, black2, black3, white1, white2;
    
    
            //通过享元工厂获取三颗黑子
            black1 = IgoChessmanFactory.getIgoChessman("b");
            black2 = IgoChessmanFactory.getIgoChessman("b");
            black3 = IgoChessmanFactory.getIgoChessman("b");
            System.out.println("判断两颗黑子是否相同:" + (black1 == black2));
    
            //通过享元工厂获取两颗白子
            white1 = IgoChessmanFactory.getIgoChessman("w");
            white2 = IgoChessmanFactory.getIgoChessman("w");
            System.out.println("判断两颗白子是否相同:" + (white1 == white2));
    
            //显示棋子,同时设置棋子的坐标位置
            black1.display(new Coordinates(1, 2));
            black2.display(new Coordinates(3, 4));
            black3.display(new Coordinates(1, 3));
            white1.display(new Coordinates(2, 5));
            white2.display(new Coordinates(2, 4));
    
        }
    }
    
    
    //坐标类:外部状态类
    class Coordinates {
        private int x;
        private int y;
    
        public Coordinates(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return this.x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return this.y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    }
    
    //围棋棋子类:抽象享元类
    abstract class IgoChessman {
        public abstract String getColor();
    
        public void display(Coordinates coord) {
            System.out.println("棋子颜色:" + this.getColor() + 
                               ",棋子位置:" + coord.getX() + "," + coord.getY());
        }
    }
    
    //黑色棋子类:具体享元类
    class BlackIgoChessman extends IgoChessman {
        public String getColor() {
            return "黑色";
        }
    }
    
    //白色棋子类:具体享元类
    class WhiteIgoChessman extends IgoChessman {
        public String getColor() {
            return "白色";
        }
    }
    
    //围棋棋子工厂类:享元工厂类,使用单例模式进行设计
    class IgoChessmanFactory {
        //使用Hashtable来存储享元对象,充当享元池
        private static Hashtable<String, IgoChessman> ht; 
    
        static {
            ht = new Hashtable<>();
            IgoChessman black, white;
            black = new BlackIgoChessman();
            ht.put("b", black);
            white = new WhiteIgoChessman();
            ht.put("w", white);
        }
    
        //通过key来获取存储在Hashtable中的享元对象
        public static IgoChessman getIgoChessman(String color) {
            return ht.get(color);
        }
    }
    
  • 优缺点
    优点:

    • 减少对象的创建,降低内存中对象的数量,较低系统的内存,提升效率;
    • 减少内存之外的其他资源占用;

    缺点:

    • 关注内 外部状态,关注线程安全问题;
    • 使系统 程序的逻辑复杂化;
  • 案例

    • java.lang.Integer#valueOf(int)
      public static Integer valueOf(int i) {
      if (i >= IntegerCache.low && i <= IntegerCache.high)
      return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);
      }

    • pool

代理模式

  • 模式动机

给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

  • 适用场景

    • 保护目标对象
    • 增强目标对象
  • 类图
    在这里插入图片描述

    class ProxyFactory {
    
        // 接收一个目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        // 返回对目标对象(target)代理后的对象(proxy)
        public Object getProxyInstance() {
            /* 执行代理对象方法时候触发 */
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),  // 目标对象使用的类加载器
                    target.getClass().getInterfaces(),   // 目标对象实现的所有接口
                    (proxy1, method, args) -> {
    
                        // 获取当前执行的方法的方法名
                        String methodName = method.getName();
                        // 方法返回值
                        Object result;
                        if ("find".equals(methodName)) {
                            // 直接调用目标对象方法
                            result = method.invoke(target, args);
                        } else {
                            System.out.println("开启事务...");
                            // 执行目标对象方法
                            result = method.invoke(target, args);
                            System.out.println("提交事务...");
                        }
                        return result;
                    }
            );
        }
    }
    public class Main {
        public static void main(String[] args) {
            //静态代理
            UserDaoProxy userDaoProxy = new UserDaoProxy();
            User user = userDaoProxy.find();
            System.out.println(user.getName());
            userDaoProxy.save(user);
    
            //动态代理
            IUserDao proxy = (IUserDao) new ProxyFactory(
                new UserDaoImpl()).getProxyInstance();
            System.out.println(proxy.getClass());
            proxy.save(user);
        }
    }
    
  • 优缺点
    优点:

    • 代理模式能将代理对象与真实被调用的目标对象分离
    • 一定程度上降低了系统的耦合度,扩展性好;
    • 保护目标对象
    • 增强目标对象

    缺点:

    • 代理模式会造成系统设计中类的数目增加;
    • 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢;
    • 增加了系统的复杂度;
  • 案例

    • java.lang.reflect.Proxy

    • org.springframework.aop.framework.AopProxy

      在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值