当前位置: 首页 > news >正文

设计模式-组合模式和建筑者模式详解

一. 组合模式

1. 背景

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

2. 定义和特点

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

(2). 优点:

  A. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;

  B. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;

(3). 缺点

  A. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;

  B. 不容易限制容器中的构件;

  C. 不容易用继承的方法来增加构件的新功能;

3. 具体实现

(1). 模式结构

  可以自身嵌套结构。

(2). 使用场景

  存储上下级关系,CEO→技术主管→员工;CEO→销售主管→员工。

(3). 代码实操

上下级自身嵌套代码:

     /// <summary>/// 员工类/// </summary>public class Employee{private string name;private string dept;private int salary;//代表下级子类private List<Employee> subordinates;//构造函数public Employee(string name, string dept, int sal){this.name = name;this.dept = dept;this.salary = sal;subordinates = new List<Employee>();}public void add(Employee e){subordinates.Add(e);}public void remove(Employee e){subordinates.Remove(e);}public List<Employee> getSubordinates(){return subordinates;}public string toString(){return ("Employee :[ Name : " + name+ ", dept : " + dept + ", salary :"+ salary + " ]");}}

测试代码:

            {// 1、树形机构的场景,使用组合模式Employee CEO = new Employee("张三", "CEO", 30000);Employee headMarketing = new Employee("李四", "技术经理", 20000);Employee headSales = new Employee("王五", "销售经理", 20000);Employee clerk1 = new Employee("赵六", "销售", 10000);Employee clerk2 = new Employee("钱七", "销售", 10000);Employee salesExecutive1 = new Employee("Tony", "技术", 10000);Employee salesExecutive2 = new Employee("Mark", "技术", 10000);CEO.add(headSales);CEO.add(headMarketing);headSales.add(clerk1);headSales.add(clerk2);headMarketing.add(salesExecutive1);headMarketing.add(salesExecutive2);//打印该组织的所有员工Console.WriteLine(CEO.toString());foreach (Employee headEmployee in CEO.getSubordinates()){Console.WriteLine(headEmployee.toString());foreach (Employee employee in headEmployee.getSubordinates()){Console.WriteLine(employee.toString());}}}

运行结果:

4. 适用场景分析

 A. 在需要表示一个对象整体与部分的层次结构的场合。

 B. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。

更多C++后台开发技术点知识内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开发,Linux内核,TCP/IP,协程,DPDK多个高级知识点。

C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址

【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取

二. 建筑者模式

1. 背景

 在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。例如,计算机是由 OPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。

 生活中这样的例子很多,如游戏中的不同角色,其性别、个性、能力、脸型、体型、服装、发型等特性都有所差异;还有汽车中的方向盘、发动机、车架、轮胎等部件也多种多样;每封电子邮件的发件人、收件人、主题、内容、附件等内容也各不相同。

 以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。

2. 定义和特点

(1). 定义

  指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

(2). 优点

 A. 各个具体的建造者相互独立,有利于系统的扩展。

 B. 客户端不必知道产品内部组成的细节,便于控制细节风险。

(3). 缺点

 A. 产品的组成部分必须相同,这限制了其使用范围。

 B. 如果产品的内部变化复杂,该模式会增加很多的建造者类。

(4). 与工厂方法模式的区别

 建造者模式注重零部件的组装过程,而工厂方模式更注重零部件的创建过程,但两者可以结合使用。

3. 具体实现

(1). 模式结构

 建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成。  

 A. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。

 B. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。

 C. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。

 D. 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

PS:如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。

结构图如下:

(2). 使用场景

 现在要构建自行车,包括核心组件frame、seat、tire,而每个组件可选的材料有多种,自行车的构建顺序是固定的,比如按照这个顺序:BuidFrame、BuildSeat、BuildTire。这个场景就可以使用建筑者模式。

(3). 代码实操

各种自行车材料代码:

    /// <summary>/// 自行车框架/// </summary>public interface IFrame{void show();}/// <summary>/// 自行车座椅/// </summary>public interface ISeat{void show();}/// <summary>/// 自行车轮胎/// </summary>public interface ITire{void show();}/// <summary>/// 合金自行车框架1/// </summary>public class AlloyFrame1 : IFrame{public void show(){Console.WriteLine("我是合金自行车框架1");}}/// <summary>/// 合金自行车框架2/// </summary>public class AlloyFrame2 : IFrame{public void show(){Console.WriteLine("我是合金自行车框架2");}}/// <summary>/// 真皮座椅1/// </summary>public class DermisSeat1 : ISeat{public void show(){Console.WriteLine("我是真皮座椅1");}}/// <summary>/// 真皮座椅2/// </summary>public class DermisSeat2 : ISeat{public void show(){Console.WriteLine("我是真皮座椅2");}}/// <summary>/// 结实的轮胎1/// </summary>public class SolidTire1 : ITire{public void show(){Console.WriteLine("我是结实的轮胎1");}}/// <summary>/// 结实的轮胎2/// </summary>public class SolidTire2 : ITire{public void show(){Console.WriteLine("我是结实的轮胎2");}}

自行车代码:

 /// <summary>/// 自行车类/// </summary>public class Bike{/// <summary>/// 自行车框架/// </summary>public IFrame frame { set; get; }/// <summary>/// 自行车座椅/// </summary>public ISeat seat { set; get; }/// <summary>/// 自行车 轮胎/// </summary>public ITire tire { set; get; }/// <summary>/// 获取自行车的详情信息/// </summary>public void GetDetils(){Console.WriteLine("自行车的详细信息如下:");frame.show();seat.show();tire.show();}}

抽象建筑者和具体建筑者:

 /// <summary>/// 抽象建筑者类/// 如果只有一个具体的建筑者类,则可以省略该抽象建筑者类的/// </summary>public abstract class AbstractBuilder{public Bike mBike = new Bike();public abstract void BuildFrame();public abstract void BuildSeat();public abstract void BuildTire();/// <summary>/// 返回自行车对象/// </summary>/// <returns></returns>public abstract Bike Build();}/// <summary>/// 自行车建筑者类1/// </summary>public class BikeBuilder1: AbstractBuilder{/// <summary>/// 构建frame/// </summary>public override void BuildFrame(){mBike.frame = new AlloyFrame1();}/// <summary>/// 构建seat/// </summary>public override void BuildSeat(){mBike.seat = new DermisSeat1();}/// <summary>/// 构建tire/// </summary>public override void BuildTire(){mBike.tire = new SolidTire1();}/// <summary>/// 返回直行车对象/// </summary>/// <returns></returns>public override Bike Build(){return mBike;}}/// <summary>/// 自行车建筑者类2/// </summary>public class BikeBuilder2 : AbstractBuilder{/// <summary>/// 构建frame/// </summary>public override void BuildFrame(){mBike.frame = new AlloyFrame2();}/// <summary>/// 构建seat/// </summary>public override void BuildSeat(){mBike.seat = new DermisSeat2();}/// <summary>/// 构建tire/// </summary>public override void BuildTire(){mBike.tire = new SolidTire2();}/// <summary>/// 返回直行车对象/// </summary>/// <returns></returns>public override Bike Build(){return mBike;}}

指挥者:

  /// <summary>/// 指挥者/// 调用建造者中的方法完成复杂对象的创建/// 如果只有一个建筑者的话,可以省略该指挥者的角色/// </summary>public class BikeDirector{private AbstractBuilder _builder;public BikeDirector(AbstractBuilder builder){this._builder = builder;}/// <summary>/// Bike的构建和组装/// </summary>/// <returns></returns>public Bike CreateBike(){_builder.BuildFrame();_builder.BuildSeat();_builder.BuildTire();return _builder.Build();}}

测试代码:

                //1.普通模式{Console.WriteLine("-------------------下面是普通模式构建自行车-------------------------");//1. 构建自行车Bike b = new Bike();b.frame = new AlloyFrame1();b.seat = new DermisSeat2();b.tire = new SolidTire1();//2. 输出自行车信息b.GetDetils();}//2. 使用建筑者模式{Console.WriteLine("-------------------下面是使用建筑者模式构建自行车-------------------------");//1. 构建建筑者BikeBuilder1 builder = new BikeBuilder1();builder.BuildFrame();builder.BuildSeat();builder.BuildTire();//2. 构建自行车Bike bike = builder.Build();//3. 输出自行车的信息bike.GetDetils();}//3. 引入抽象建筑者父类{Console.WriteLine("-------------------下面是 引入抽象建筑者父类 构建自行车-------------------------");//1. 构建建筑者1AbstractBuilder builder = new BikeBuilder1();builder.BuildFrame();builder.BuildSeat();builder.BuildTire();//2. 构建自行车Bike bike = builder.Build();//3. 输出自行车的信息bike.GetDetils();//1. 构建建筑者2AbstractBuilder builder2 = new BikeBuilder2();builder2.BuildFrame();builder2.BuildSeat();builder2.BuildTire();//2. 构建自行车Bike bike2 = builder2.Build();//3. 输出自行车的信息bike2.GetDetils();}//4. 引入指挥者{Console.WriteLine("-------------------下面是 引入指挥者 构建自行车-------------------------");//指挥者1BikeDirector dirctor1 = new BikeDirector(new BikeBuilder1());Bike bike1 = dirctor1.CreateBike();bike1.GetDetils();//指挥者2BikeDirector dirctor2 = new BikeDirector(new BikeBuilder2());Bike bike2 = dirctor2.CreateBike();bike2.GetDetils();}

运行效果:

4. 适用场景分析

 建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。

 A. 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。

 B. 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。

原文链接:https://www.cnblogs.com/yaopengfei/p/13462519.html

相关文章:

设计模式-组合模式和建筑者模式详解

一. 组合模式 1. 背景 在现实生活中&#xff0c;存在很多“部分-整体”的关系&#xff0c;例如&#xff0c;大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。在软件开发中也是这样&#xff0c;例如&…...

Pcap文件的magic_number

1. 简述 pcap文件头中的magicNum是来标识pcap文件文件头和包头字节序和应用是否一致的。 在标准情况下为0xa1b2c3d4。如果相反则说明需要调换字节序。 一般格式 Global Header Packet Header Packet Data Packet Header Packet Data ....pcap文件头格式 typedef struct pca…...

MDS75-16-ASEMI三相整流模块MDS75-16

编辑-Z MDS75-16在MDS封装里采用的6个芯片&#xff0c;是一款工业焊机专用大功率整流模块。MDS75-16的浪涌电流Ifsm为920A&#xff0c;漏电流(Ir)为5mA&#xff0c;其工作时耐温度范围为-40~150摄氏度。MDS75-16采用GPP硅芯片材质&#xff0c;里面有6颗芯片组成。MDS75-16的电…...

基本TCP编程

1. 基本概念 TCP (即传输控制协议) 是一种面向连接的传输层协议,它能提供高可靠性通信 (即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。 2. 通信流程解析 TCP 通信的流程与打电话的过程相似,以下以一对情侣打电话的过程来展示TCP的通信流程: 其中服务端 …...

【沁恒WCH CH32V307V-R1开发板读取板载温度实验】

【沁恒WCH CH32V307V-R1开发板读取板载温度实验】1. 前言2. 软件配置2.1 安装MounRiver Studio3. ADC项目测试3.1 打开ADC工程3.2 编译项目4. 下载验证4.1 接线4.2 演示效果5. 小结1. 前言 ADC 模块包含 2 个 12 位的逐次逼近型的模拟数字转换器&#xff0c;最高 14MHz 的输入时…...

学习SpringCloudAlibaba(二)微服务的拆分与编写

目录 一、单体架构VS微服务架构 1.单体架构 ​&#xff08;1&#xff09;.单体架构的优点 &#xff08;2&#xff09;.单体架构的缺点 2.微服务架构 &#xff08;1&#xff09;微服务的特性 &#xff08;2&#xff09;微服务架构图 &#xff08;3&#xff09;微服务的优点 …...

通过对HashMap的源码分析解决部分关于HashMap的问题

HashMap第一次分配多大的空间我们查看resize&#xff08;)中的源码所以当我们没有传入默认容量的参数的时候&#xff0c;默认容量是16当传进一个20的初始参数时&#xff0c;数组的容量是多大所以当我们传入20的参数&#xff0c;这时创建的容量是32&#xff08;2^5&#xff09;对…...

【无标题】

Windeployqt 打包,缺少DLL 的原因分析,解决方法 很多同学使用工具windeployqt进行打包发布后,运行exe文件时,还是会出现下图所示的系统错误提示,这种情况就表示相关的DLL 库文件没有被正确打包。可是windeployqt明确显示运行正常啊,难道是QT自家的windeployqt这个工具有…...

渗透测试 -- 网站信息收集

数据来源 01 网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件(web容器)、脚本语言&#xff08;php、java、...&#xff09;、数据库&#xff08;Mysql、...&#xff09;为什么要了解这些&#xff1f; 举个例子&#xff1a;发现了一…...

Windows 搭建ARM虚拟机 UOS系统

搭建环境安装虚拟机下载虚拟机QEMU&#xff0c;https://www.qemu.org/download/&#xff0c;目前最新版本是7.2.0。安装完成后&#xff0c;需要将qemu的安装路径设置到环境变量完成后运行cmd&#xff0c;测试环境变量配置完成。qemu-system-aarch64 --version如上截图所示&…...

day58每日温度_下一个更大元素1

力扣739.每日温度 题目链接&#xff1a;https://leetcode.cn/problems/daily-temperatures/ 思路 什么时候用单调栈呢&#xff1f; 通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置&#xff0c;此时我们就要想到可以用单调栈了…...

超清遥感影像语义分割处理

分割出城市中的垃圾堆场,遂寻找到了 UrbanAtlas 2012 database 这个数据集和对应的 baseline baseline IoU for class 1: 0.5667 IoU for class 2: 0.3504 IoU for class 3: 0.0001 IoU for class 4: 0.0002 IoU for class 5: 0.4121 IoU for class 6: 0.0204 IoU for cla…...

RabbitMQ安装及配置

目录1.下载和安装1.1 下载1.2. 安装1.3 测试1.4 卸载管理界面2.1 添加用户2.2 创建Virtual Hosts2.3. 设置权限1.下载和安装 1.1 下载 1.下载Erlang的rpm包 RabbitMQ是Erlang语言编写&#xff0c;所以Erang环境必须要有&#xff0c;注&#xff1a;Erlang环境一定要与RabbitMQ…...

网络协议(四):网络互联模型、物理层、数据链路层

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 网络协议(二)&#xff1a;MAC地址、IP地址、子网掩码、子网和超网 网络协议(三)&#xff1a;路由器原理及数据包传输过程 网络协议(四)&#xff1a;网络互联模型、物理层、数据链路层 目录一、网…...

请问有没有关于数据预测的方法?

利用数据对未来进行预测分析&#xff0c;虽然不能百分百的准确预测&#xff0c;但是有数据理论支撑的趋势预测是客观可靠的。当数据分析的目的涉及未来决策时&#xff0c;就可以大胆使用预测的思路和方法&#xff0c;如企业明年的战略计划、销售计划等&#xff0c;这对企业而言…...

[CVPR 2021] Your “Flamingo“ is My “Bird“: Fine-Grained, or Not

Contents Your "Flamingo" is My "Bird"MethodCooperation or Confrontation?Disentanglement and ReinforcementExperimentDiscussionsReferencesYour “Flamingo” is My “Bird” 对于如下图片,FGVC 的目标是让模型识别出 “flamingo”,但对于大部分…...

clickHouse笔记

1、介绍 clickHouse将数据进行分成多个partition&#xff0c;多个CUP进行进行单条的Query&#xff0c;不适合qps特别高的查询场景&#xff1b;适应场景&#xff1a;处理过的&#xff0c;字段特别大的宽表&#xff0c;进行统计&#xff0c;查询&#xff0c;聚合等数据分析场景 …...

10.jQuery中请求预处理 $.ajaxPrefilter()

在使用jQuery发起请求的时候($.get(),$.post().$ajax()都可以)会默认在请求前调用$.ajaxPrefilter()这个函数&#xff0c;我们可以利用这个来做一些事情 目录 1 定义API根路径 2 添加请求头 3 添加请求结束的回调函数 1 定义API根路径 这样后面每次请求就不用再写根路…...

【黄啊码】浅谈PHP入门|如何学习PHP

大家好&#xff0c;我是黄啊码&#xff0c;很多小白问我&#xff0c;怎么入门PHP&#xff0c;甚至连PHP能干嘛都不知道&#xff0c;今天啊码就具体来讲讲。 什么是PHP PHP是一种开源的通用脚本语言&#xff0c;用于创建动态网页和应用程序。它可以运行在服务器端&#xff0c;…...

人大金仓数据库的归档日志

归档日志 归档日志是非活动的WAL日志备份。通过使用归档日志&#xff0c;可以保留所有WAL日志的历史记录&#xff0c;当数据库处于ARCHIVELOG模式并进行日志切换时&#xff0c;后台进程archiver process会将WAL日志的内容保存到归档日志中&#xff0c;当数据库出现介质失败时&…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...