【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录

  • 案例引入
    • 学校院系展示
  • 介绍
    • 基本介绍
    • 使用场景
    • 登场角色
  • 案例实现
    • 案例1
      • 类图
      • 代码实现
    • 案例2
      • 类图
      • 代码实现
      • 拓展
  • 组合模式在JDK的HashMap源码中的应用
  • 组合模式总结
  • 文章说明

案例引入

学校院系展示

编写程序展示一个学校院系结构: 需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系

在这里插入图片描述

【传统方式】

将学院看做是学校的子类,系是学院的子类,小的组织继承大的组织

分析: 在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系, 因此这种方案,不能很好实现管理操作,比如对学院、系的添加,删除,遍历

【组合模式】

把学校、院、系都看做是组织结构,他们之间没有继承的关系,而是一个树形结构,可以更好的实现管理操作

介绍

基本介绍

  • 组合模式,又叫部分整体模式(描述部分和整体的关系),它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系
  • 组合模式依据树形结构(容器中可以放入内容,也可以放入小容器,小容器中又可以放入内容或者更小的容器)来组合对象,用来表示部分以及整体层次。组合模式可以使容器与内容具有一致性,创造出递归结构
  • 组合模式属于结构型模式
  • 组合模式使得用户对单个对象和组合对象的访问具有一致性,组合能让客户以一致的方式处理个别对象以及组合对象

使用场景

组合模式解决这样的问题,当我们的要处理的对象可以生成一个树形结构,而我们要对树上的节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子

在这里插入图片描述

登场角色

  • Leaf(树叶):表示“内容”的角色,里面不能放人其他对象,即没有孩子,其定义组合内元素的行为
  • Composite(复合物):表示容器的角色,可以在其中放入Leaf和Composite,有一些对子部件的相关操作(如增加、删除),可能不具有叶子的某种行为
  • Component:使Leaf和Composite具有一致性的角色,Composite是 Leaf和Composite的父类。Compnet是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component子部件,Component 可以是抽象类或者接口
  • Client:使用Composite模式的角色

在这里插入图片描述

案例实现

案例1

类图

在这里插入图片描述

代码实现

【Component:组织】

package com.atguigu.composite;

/**
 * 组织,如论是系、学院还是学校,都属于组织
 */
public abstract class OrganizationComponent {

    /**
     * 名字
     */
    private String name;
    /**
     * 说明
     */
    private String des;

    /**
     * 为什么需要默认实现,而不是写成抽象方法呢?
     * 因为叶子节点不需要实现add方法,如果是抽象方法的话,就要实现了,有点多余
     * @param organizationComponent
     */
    protected void add(OrganizationComponent organizationComponent) {
        //默认实现,抛出不支持操作异常
        throw new UnsupportedOperationException();
    }

    protected void remove(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }

    /**
     * 构造器
     * @param name
     * @param des
     */
    public OrganizationComponent(String name, String des) {
        super();
        this.name = name;
        this.des = des;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    /**
     * 打印方法, 做成抽象的, 子类都需要实现
     */
    protected abstract void print();
    
}

【Composite:大学】

package com.atguigu.composite;

import java.util.ArrayList;
import java.util.List;

/**
 * University 就是 Composite角色 , 可以管理College
 */
public class University extends OrganizationComponent {

   List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

   /**
    * 构造器
    * @param name
    * @param des
    */
   public University(String name, String des) {
      super(name, des);
   }

   /**
    * 重写add
    * @param organizationComponent
    */
   @Override
   protected void add(OrganizationComponent organizationComponent) {
      organizationComponents.add(organizationComponent);
   }

   /**
    * 重写remove
    * @param organizationComponent
    */
   @Override
   protected void remove(OrganizationComponent organizationComponent) {
      organizationComponents.remove(organizationComponent);
   }

   @Override
   public String getName() {
      return super.getName();
   }

   @Override
   public String getDes() {
      return super.getDes();
   }

   /**
    * print方法,就是输出 University 包含的学院
    */
   @Override
   protected void print() {
      // 先输出学校的名字
      System.out.println("--------------" + getName() + "--------------");
      // 遍历 organizationComponents,其实就是遍历出学校的学院
      for (OrganizationComponent organizationComponent : organizationComponents) {
         organizationComponent.print();
      }
   }

}

【Composite:学院】

package com.atguigu.composite;

import java.util.ArrayList;
import java.util.List;

public class College extends OrganizationComponent {

   /**
    * 存储系
    */
   List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

   /**
    * 构造器
    * @param name
    * @param des
    */
   public College(String name, String des) {
      super(name, des);
   }

   @Override
   protected void add(OrganizationComponent organizationComponent) {
      // 将来实际业务中,Colleage 的 add 和  University add 不一定完全一样
      organizationComponents.add(organizationComponent);
   }

   @Override
   protected void remove(OrganizationComponent organizationComponent) {
      organizationComponents.remove(organizationComponent);
   }

   @Override
   public String getName() {
      return super.getName();
   }

   @Override
   public String getDes() {
      return super.getDes();
   }

   /**
    * print方法,就是输出学院包含的系
    */
   @Override
   protected void print() {
      System.out.println("--------------" + getName() + "--------------");
      // 遍历 organizationComponents
      for (OrganizationComponent organizationComponent : organizationComponents) {
         organizationComponent.print();
      }
   }


}

【Composite:系】

package com.atguigu.composite;

public class Department extends OrganizationComponent {

   //没有子节点,所以不用声明集合

   public Department(String name, String des) {
      super(name, des);
   }


   //add , remove 就不用写了,因为他是叶子节点

   @Override
   public String getName() {
      return super.getName();
   }

   @Override
   public String getDes() {
      return super.getDes();
   }

   @Override
   protected void print() {
      // 没有子节点,不需要输入其他东西
      System.out.println(getName());
   }

}

【Client】

package com.atguigu.composite;

public class Client {

   public static void main(String[] args) {
      //创建大学
      OrganizationComponent university = new University("清华大学", " 中国顶级大学 ");

      //创建大学的各个学院
      OrganizationComponent computerCollege = new College("计算机学院", " 计算机学院 ");
      OrganizationComponent infoEngineerCollege = new College("信息工程学院", " 信息工程学院 ");

      //创建各个学院下面的系(专业)
      computerCollege.add(new Department("软件工程", " 软件工程不错 "));
      computerCollege.add(new Department("网络工程", " 网络工程不错 "));
      computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业 "));
      infoEngineerCollege.add(new Department("通信工程", " 通信工程不好学 "));
      infoEngineerCollege.add(new Department("信息工程", " 信息工程好学 "));

      //将学院加入到 学校
      university.add(computerCollege);
      university.add(infoEngineerCollege);

      //输出大学的各个组织
      university.print();
   }

}

【运行】

--------------清华大学--------------
--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术
--------------信息工程学院--------------
通信工程
信息工程

Process finished with exit code 0

【只打印某个学院的组织结构】

computerCollege.print();

【运行】

--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术

Process finished with exit code 0

案例2

类图

在这里插入图片描述

代码实现

【Component:Entry类】

package com.atguigu.composite.Sample;

/**
 * 目录条目类 用来实现 File类 和 Directory类 的一致性
 */
public abstract class Entry {

    /**
     * 获取名字
     *
     * @return
     */
    public abstract String getName();

    /**
     * 获取大小
     *
     * @return
     */
    public abstract int getSize();

    /**
     * 加入目录条目,向文件夹中放入文件或者文件夹(Directory类来具体实现)
     *
     * @param entry
     * @return
     * @throws FileTreatmentException
     */
    public Entry add(Entry entry) throws FileTreatmentException {
        throw new FileTreatmentException();
    }

    /**
     * 为一览加上前缀并显示目录条目一览
     */
    public void printList() {
        printList("");
    }

    /**
     * 为一览加上前缀
     * protected修饰:只能被子类调用
     * @param prefix
     */
    protected abstract void printList(String prefix);

    /**
     * 显示代表类的文字
     *
     * @return
     */
    public String toString() {
        // 将文件名和文件大小一起显示出来
        return getName() + " (" + getSize() + ")";
    }
}

方法的默认实现是抛异常(一般都是这样做),这样如果子类没有重写该方法的话,就会抛异常

【Composite:文件类】

package com.atguigu.composite.Sample;

/**
 * 文件类
 */
public class File extends Entry {
    private String name;
    private int size;

    /**
     * 构造方法 创建文件
     *
     * @param name
     * @param size
     */
    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    protected void printList(String prefix) {
        // 直接写this,会自动调用该类的toString()方法的
        System.out.println(prefix + "/" + this);
    }
}

【Composite:目录类】

package com.atguigu.composite.Sample;

import java.util.ArrayList;
import java.util.Iterator;

public class Directory extends Entry {
    /**
     * 文件夹的名字
     */
    private String name;
    /**
     * 文件夹中目录条目的集合
     */
    private ArrayList directory = new ArrayList();

    public Directory(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    /**
     * 获取大小:计算子文件或文件夹的大小总和
     * @return
     */
    @Override
    public int getSize() {
        int size = 0;
        Iterator it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            // 无论子条目是文件夹还是文件,都可以直接调用其getSize()方法,这就是“容器与内容一致性”的好处
            // 如果entry是目录,就会形成递归调用
            size += entry.getSize();
        }
        return size;
    }

    /**
     * 增加目录条目
     * @param entry
     * @return
     */
    @Override
    public Entry add(Entry entry) {
        directory.add(entry);
        return this;
    }

    /**
     * 显示目录条目一览
     * @param prefix
     */
    @Override
    protected void printList(String prefix) {
        System.out.println(prefix + "/" + this);
        Iterator it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            // 也是递归调用
            entry.printList(prefix + "/" + name);
        }
    }
}

【自定义异常类】

package com.atguigu.composite.Sample;

/**
 * 自定义异常类
 */
public class FileTreatmentException extends RuntimeException {
    public FileTreatmentException() {
    }

    public FileTreatmentException(String msg) {
        super(msg);
    }
}

【主类】

package com.atguigu.composite.Sample;

public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("Making root entries...");
            Directory rootdir = new Directory("root");
            Directory bindir = new Directory("bin");
            Directory tmpdir = new Directory("tmp");
            Directory usrdir = new Directory("usr");
            rootdir.add(bindir);
            rootdir.add(tmpdir);
            rootdir.add(usrdir);
            bindir.add(new File("vi", 10000));
            bindir.add(new File("latex", 20000));
            rootdir.printList();

            System.out.println("");
            System.out.println("Making user entries...");
            Directory yuki = new Directory("yuki");
            Directory hanako = new Directory("hanako");
            Directory tomura = new Directory("tomura");
            usrdir.add(yuki);
            usrdir.add(hanako);
            usrdir.add(tomura);
            yuki.add(new File("diary.html", 100));
            yuki.add(new File("Composite.java", 200));
            hanako.add(new File("memo.tex", 300));
            tomura.add(new File("game.doc", 400));
            tomura.add(new File("junk.mail", 500));
            rootdir.printList();
        } catch (FileTreatmentException e) {
            e.printStackTrace();
        }
    }
}

【运行】

Making root entries...
/root (30000)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (0)

Making user entries...
/root (31500)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (1500)
/root/usr/yuki (300)
/root/usr/yuki/diary.html (100)
/root/usr/yuki/Composite.java (200)
/root/usr/hanako (300)
/root/usr/hanako/memo.tex (300)
/root/usr/tomura (900)
/root/usr/tomura/game.doc (400)
/root/usr/tomura/junk.mail (500)

Process finished with exit code 0

拓展

如何通过修改或者补充上面的代码来增加一个为 文件/目录 获取完整路径的功能,如/root/usr/yuki/Composite.java

【Component】

添加一个记录父条目的变量,和一个公共方法,该方法不需要子类去重写,因为实现逻辑都一样,如果不一样的话,就需要写成抽象方法

package com.atguigu.composite.A1;

public abstract class Entry {
    protected Entry parent;

    public abstract String getName();

    public abstract int getSize();

    public Entry add(Entry entry) throws FileTreatmentException {
        throw new FileTreatmentException();
    }

    public void printList() {
        printList("");
    }

    protected abstract void printList(String prefix);

    public String toString() {
        return getName() + " (" + getSize() + ")";
    }


    /**
     * 获取条目的完整路径
     *
     * @return
     */
    public String getFullName() {
        StringBuffer fullname = new StringBuffer();
        Entry entry = this;
        do {
            //需要将父条目的名字插到前面,而不是append到后面
            fullname.insert(0, "/" + entry.getName());
            entry = entry.parent;
        } while (entry != null);
        return fullname.toString();
    }
}

【Composite:目录类】

当给目录加入元素时,需要指定元素的父元素,使用entry.parent = this; 来实现

package com.atguigu.composite.A1;

import java.util.ArrayList;
import java.util.Iterator;

public class Directory extends Entry {
    private String name;
    private ArrayList directory = new ArrayList();
    public Directory(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public int getSize() {
        int size = 0;
        Iterator it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry)it.next();
            size += entry.getSize();
        }
        return size;
    }
    public Entry add(Entry entry) {
        directory.add(entry);
        entry.parent = this;                
        return this;
    }
    protected void printList(String prefix) {
        System.out.println(prefix + "/" + this);
        Iterator it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry)it.next();
            entry.printList(prefix + "/" + name);
        }
    }
}

组合模式在JDK的HashMap源码中的应用

在这里插入图片描述

  • Map 就是一个抽象的构建 (类似我们的Component)
  • HashMap是一个中间的构建(Composite), 实现/继承了相关方法(put, putAll)
  • Node 是 HashMap的静态内部类,类似Leaf叶子节点, 该类没有(put, putAll)这些方法
    • ​ static class Node<K,V> implements Map.Entry<K,V>

组合模式总结

  • 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题
  • 具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动
  • 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的树形结构
  • 需要遍历组织机构,或者处理的对象具有树形结构时,非常适合使用组合模式
  • 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/51575.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EXCEL,如何比较2个表里的数据差异(使用数据透视表)

目录 1 问题: 需要比较如下2个表的内容差异 1.1 原始数据喝问题 1.2 提前总结 2 使用EXCEL公式方法 2.1 新增辅助列&#xff1a; 辅助index 2.2 具体公式 配合条件格式 使用 3 数据透视表方法 3.1 新增辅助列&#xff1a; 辅助index 3.2 需要先打开 数据透视表向导 …

CMU 15-445 -- Multi-Version Concurrency Control - 16

CMU 15-445 -- Multi-Version Concurrency Control - 16 引言MVCCExample #1Example #2小结 Design DecisionsConcurrency Control ProtocolVersion StorageAppend-Only StorageTime-Travel StorageDelta Storage Garbage CollectionTuple-Level GCTransaction-Level GC Index …

linux系统安装mysql

背景 之前用docker安装mysql&#xff0c;受限太多&#xff0c;这次不用docker直接安装。 参考文章 linux系统安装mysql 文章写的很细&#xff0c;亲测有效。 问题记录 不过存在一个小问题&#xff0c;这里记录一下自己的解决方法 问题&#xff1a;安装完mysql&#xff0c;启…

MD-MTSP:成长优化算法GO求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、成长优化算法GO 成长优化算法&#xff08;Growth Optimizer&#xff0c;GO&#xff09;由Qingke Zhang等人于2023年提出&#xff0c;该算法的设计灵感来源于个人在成长过程中的学习和反思机制。学习是个人通过从外部世界获取知识而成长的过程&#xff0c;反思是检查个体自…

【物联网无线通信技术】UWB定位从理论到实现(DW1000)

超宽带&#xff08;UWB&#xff09;是一种基于IEEE 802.15.4a和802.15.4z标准的无线电技术&#xff0c;可以非常精确地测量无线电信号的飞行时间&#xff0c;从而实现厘米级精度的距离/位置测量。UWB技术除了提供定位功能外&#xff0c;它本身是一种通信技术&#xff0c;其提供…

Labelme制作COCO格式的图像语义分割数据集

1.按照labelme工具地址先配置安装labelme&#xff1a;GitHub - wkentaro/labelme: Image Polygonal Annotation with Python (polygon, rectangle, circle, line, point and image-level flag annotation). 2.给自己的数据集画多边形框-Create Polygons 每张图像画完框后&#…

[个人笔记] vCenter设置时区和NTP同步

VMware虚拟化 - 运维篇 第三章 vCenter设置时区和NTP同步 VMware虚拟化 - 运维篇系列文章回顾vCenter设置时区和NTP同步&#xff08;附加&#xff09;ESXi设置alias参考链接 系列文章回顾 第一章 vCenter给虚机添加RDM磁盘 第二章 vCenter回收活跃虚拟机的剩余可用空间 vCente…

linux+Jenkins+飞书机器人发送通知(带签名)

文章目录 &#x1f31e;如何使用&#x1f33b;在linux 上安装python 环境&#x1f33b;发送消息python脚本&#x1f98b;把脚本上传倒linux上&#x1f98b;jenkins 上执行脚本 &#x1f31e;如何使用 自定义机器人使用指南飞书官网https://open.feishu.cn/document/client-doc…

ChatGPT炒股:爬取股票官方微信公众号的新闻资讯

上市公司的微信公众号&#xff0c;现在已经成为官网之外最重要的官方信息发布渠道。有些不会在股票公告中发布的消息&#xff0c;也会在微信公众号进行发布。所以&#xff0c;跟踪持仓股票的公众号信息&#xff0c;非常重要。 下面&#xff0c;以贝特瑞的官方公众号“贝特瑞新…

beego验证码(配置到redis存储)

我们定义一个全局变量用于存储redis连接 RedisDb *redis.Client 然后连接 redis 这一块我们将redis信息写到app.conf文件里了&#xff1a; redisDb 1 redisAddr "127.0.0.1:6379" redisPwd "" package initializeimport ("beego_learning/global&q…

经典的数组和指针结合的OJ题

一、合并两个有序数组 leetcode链接 题目描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递…

[Linux]进程控制详解!!(创建、终止、等待、替换)

hello&#xff0c;大家好&#xff0c;这里是bang___bang_&#xff0c;在上两篇中我们讲解了进程的概念、状态和进程地址空间&#xff0c;本篇讲解进程的控制&#xff01;&#xff01;包含内容有进程创建、进程等待、进程替换、进程终止&#xff01;&#xff01; 附上前2篇文章…

七大经典比较排序算法

1. 插入排序 (⭐️⭐️) &#x1f31f; 思想&#xff1a; 直接插入排序是一种简单的插入排序法&#xff0c;思想是是把待排序的数据按照下标从小到大&#xff0c;依次插入到一个已经排好的序列中&#xff0c;直至全部插入&#xff0c;得到一个新的有序序列。例如&#xff1a;…

Vue3搭建启动

Vue3搭建&启动 一、创建项目二、启动项目三、配置项目1、添加编辑器配置文件2、配置别名3、处理sass/scss4、处理tsx(不用的话可以不处理) 四、添加Eslint 一、创建项目 npm create vite 1.project-name 输入项目名vue3-vite 2.select a framework 选择框架 3.select a var…

【Spring】聊聊Spring如何解决的循环依赖以及三级缓存

循环依赖是什么 在平时的面试中&#xff0c;只要问到Spring&#xff0c;那么大概率肯定会问什么是循环依赖&#xff0c;Sping是如何解决循环依赖的。以及三级缓存机制是什么。所以为了从根本上解决这个问题&#xff0c;本篇主要详细介绍一下循环依赖的问题。 Spring Bean初始…

谷粒商城第七天-商品服务之分类管理下的分类的拖拽功能的实现

目录 一、总述 1.1 前端思路 1.2 后端思路 二、前端实现 2.1 判断是否能进行拖拽 2.2 收集受影响的节点&#xff0c;提交给服务器 三、后端实现 四、总结 一、总述 这个拖拽功能对于这种树形的列表&#xff0c;整体的搬迁是很方便的。但是其实现却并不是那么的简单。 …

Android SDK 上手指南||第一章 环境需求||第二章 IDE:Eclipse速览

第一章 环境需求 这是我们系列教程的第一篇&#xff0c;让我们来安装Android的开发环境并且把Android SDK运行起来&#xff01; 介绍 欢迎来到Android SDK入门指南系列文章&#xff0c;如果你想开始开发Android App&#xff0c;这个系列将从头开始教你所须的技能。我们假定你…

Vue2封装自定义全局Loading组件

前言 在开发的过程中&#xff0c;点击提交按钮&#xff0c;或者是一些其它场景总会遇到Loading加载框&#xff0c;PC的一些UI库也没有这样的加载框&#xff0c;无法满足业务需求&#xff0c;因此可以自己自定义一个&#xff0c;实现过程如下。 效果图 如何封装&#xff1f; 第…

MySQL | 常用命令示例

MySQL | 常用命令示例 一、启停MySQL数据库服务二、连接MySQL数据库三、创建和管理数据库四、创建和管理数据表五、数据备份和恢复六、查询与优化 MySQL是一款常用的关系型数据库管理系统&#xff0c;广泛应用于各个领域。在使用MySQL时&#xff0c;我们经常需要编写一些常用脚…

Qt之切换语言的方法(传统数组法与Qt语言家)

http://t.csdn.cn/BVigB 传统数组法&#xff1a; 定义一个字符串二维数组&#xff0c; QString weekStr[2][7] {"星期一","星期二","星期三","星期四","星期五","星期六","星期日",\ "Monday&…