设计模式(四)行为型模式介绍及实例(上)
文章目录
- 一、模板模式
- 1.1 模板模式定义
- 1.2 模板模式特点
- 1.3 模板模式主要角色
- 1.4 模板模式实现方式
- 1.5 模板模式应用场景
- 二、策略模式
- 2.1 策略模式定义
- 2.2 策略模式主要角色
- 2.3 策略模式特点
- 2.4 策略模式实现方式
- 2.5 策略模式应用场景
- 三、状态模式
- 3.1 状态模式定义
- 3.2 状态模式主要角色
- 3.3 状态模式特点
- 3.4 状态模式实现方式
- 3.5 状态模式应用场景
- 四、观察者模式
- 4.1 观察者模式定义
- 4.2 观察者模式主要角色
- 4.3 观察者模式特点
- 4.4 观察者模式实现方式
- 4.5 观察者模式应用场景
- 五、备忘录模式
- 5.1 备忘录模式定义
- 5.2 备忘录模式主要角色
- 5.3 备忘录模式特点
- 5.4 备忘录模式实现方式
- 5.5 备忘录模式应用场景
本系列文章共分为六篇:
设计模式(一)设计模式的分类与区别
设计模式(二)创建型模式介绍及实例
设计模式(三)结构型模式介绍及实例
设计模式(四)行为型模式介绍及实例(上)
设计模式(五)行为型模式介绍及实例(下)
设计模式(六)设计模式的常见应用
上篇文件介绍了结构型模式,本篇将介绍行为型模式。行为型模式的主要关注点是“描述类或对象之间怎样通信、协作共同完成任务,以及怎样分配职责
”。因为行为型模式较多,分成上下两篇来介绍。
一、模板模式
1.1 模板模式定义
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中
,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
一句话总结:父类定义固定的框架和公共部分,子类实现可变部分/步骤。
1.2 模板模式特点
优点:
- 它
封装了不变部分,扩展可变部分
。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。 - 它
在父类中提取了公共的部分代码
,便于代码复用。 - 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
1.3 模板模式主要角色
模板方法模式UML图示:
- 抽象类
负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下:
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写
。
基本方法:是整个算法中的一个步骤,包含以下几种类型:
1>抽象方法:在抽象类中申明,由具体子类实现。
2>具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
3>钩子方法
:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
- 具体子类
实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
1.4 模板模式实现方式
此处,以两个人张三和李四上班为例,主要涉及三个部分:起床、吃早饭、乘坐交通工具去上班,起床是公共方法,吃早饭可以推迟到之类,乘什么样的交通工具可以用钩子方法来判别。示例代码如下:
/*抽象类*/
abstract class Worker {public void WorkerWay() {getUp();haveBreakfast();if(!haveCar()){takeBus(); }else{drive();}} /*具体方法*/public void getUp() {System.out.println("起床");}public void takeBus(){System.out.println("坐公交上班");}public void drive(){System.out.println("开车上班");}/*钩子方法*/public boolean haveCar(){ return true; }/*抽象方法*/public abstract void haveBreakfast();
}
/*具体子类:张三*/
public class Zhangsan extends Worker{@Overridepublic void haveBreakfast() {System.out.println("吃三明治、喝牛奶");}public boolean haveCar(){ return false; }
}
/*具体子类:李四*/
public class Lisi extends Worker{@Overridepublic void haveBreakfast() {System.out.println("吃包子、喝豆浆");}public boolean haveCar(){ return true; }
}
/*测试类*/
public class TemplateTest {public static void main(String[] args) { Zhangsan zhangsan =new Zhangsan();System.out.println("张三的上班方式:");zhangsan.WorkerWay();Lisi lisi =new Lisi();System.out.println("李四的上班方式:");lisi.WorkerWay(); }
}
结果如下:
张三的上班方式:
起床
吃三明治、喝牛奶
开车上班
李四的上班方式:
起床
吃包子、喝豆浆
坐公交上班
1.5 模板模式应用场景
算法的整体步骤很固定,但其中个别部分易变
时,这时候可以使用模板方法模式,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复
。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。- 当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数(见“模板方法模式的扩展”)约束其行为。
二、策略模式
2.1 策略模式定义
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换
,且算法的变化不会影响使用算法的客户。
一句话总结:有多种算法,供客户端替换使用。
2.2 策略模式主要角色
策略模式的UML类图如下:
Strategy类,定义所有支持的算法的公共接口;ConcreteStrategy类,封装了具体的算法或行为;Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。
注意事项:具体策略数量超过 4 个,则需要考虑使用混合模式。
2.3 策略模式特点
优点:
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
- 可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
- 提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
- 把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
缺点:
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
- 策略模式造成很多的策略类。
2.4 策略模式实现方式
此处,以小明做饭为例,当他想吃面时,做了一份臊子面;想吃饭时,做了一份炒饭。示例代码如下:
/*抽象策略*/
public interface Cook {public void cooking();
}
/*具体策略:做面*/
public class NoodleCook implements Cook{public void cooking() {System.out.println("做了一份臊子面");}
}
/*具体策略:做饭*/
public class RiceCook implements Cook{public void cooking() {System.out.println("做了一份炒饭");}
}
/*环境类*/
public class Context {private Cook cook;public Cook getCook(){ return cook; }public void setCook(Cook cook){this.cook=cook;}public void cooking(){cook.cooking();}
}
/*测试类*/
public class StrategyTest {public static void main(String[] args) { Context context = new Context();System.out.println("小明要吃面");Cook cook = new NoodleCook();context.setCook(cook);context.cooking();System.out.println("小明要吃饭");cook = new RiceCook();context.setCook(cook);context.cooking();}
}
结果如下:
小明要吃面
做了一份臊子面
小明要吃饭
做了一份炒饭
2.5 策略模式应用场景
- 一个系统需要
动态地在几种算法中选择一种
时,可将每个算法封装到策略类中。 - 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
- 系统中
各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节
时。 - 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
- 多个类的区别仅仅在表现行为不同,可以使用策略模式,在
运行时动态选择具体要执行的行为
。 - 算法需要自由切换的场景。
三、状态模式
3.1 状态模式定义
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
一句话总结:对象的行为依赖于其状态,将状态提取为对象,降低对象之间的耦合。
3.2 状态模式主要角色
状态模式UML图示如下:
State类是抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState是具体的状态类,每一个子类实现一个与Context的一个状态相关的行为。
Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态。
3.3 状态模式特点
优点:
- 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
减少对象间的相互依赖
。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。- 有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
缺点:
- 状态模式的使用必然会增加系统的类与对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
3.4 状态模式实现方式
此处,以档位切换为例,某个开关有3个档位,且遵从高 --> 中 --> 低 --> 高的切换方式。示例代码如下:
/*抽象状态*/
public abstract class Switch {public abstract void setPre(Context context);public abstract void setNext(Context context);
}
/*具体状态1:低档位*/
public class LowSwitch extends Switch{@Overridepublic void setPre(Context context) {System.out.println("当前是低档位,向前切换为中档位");context.setSwitch(new MiddSwitch());}@Overridepublic void setNext(Context context) {System.out.println("当前是低档位,向后切换为高档位");context.setSwitch(new HighSwitch());}@Overridepublic String toString() { return "低档位"; }
}
/*具体状态2:中档位*/
public class MiddSwitch extends Switch{@Overridepublic void setPre(Context context) {System.out.println("当前是中档位,向前切换为高档位");context.setSwitch(new HighSwitch());}@Overridepublic void setNext(Context context) {System.out.println("当前是中档位,向后切换为低档位");context.setSwitch(new LowSwitch());}
}
/*具体状态3:高档位*/
public class HighSwitch extends Switch{@Overridepublic void setPre(Context context) {System.out.println("当前是高档位,向前切换为低档位");context.setSwitch(new LowSwitch());}@Overridepublic void setNext(Context context) {System.out.println("当前是高档位,,向后切换为中档位");context.setSwitch(new MiddSwitch());}
}
/*环境类*/
public class Context {private Switch switch1;//定义环境类的初始状态public Context(){this.switch1 = new LowSwitch();}//设置档位public void setSwitch(Switch sw){switch1 = sw;}//读取档位public Switch getSwitch(){System.out.println("当前档位是:"+switch1.toString());return(switch1);}//往前设置一个档位public void setPre(){switch1.setPre(this);}//往后设置一个档位public void setNext(){switch1.setNext(this);}
}
/*测试类*/
public class SwtichTest {public static void main(String[] args){Context context=new Context(); //创建环境 context.getSwitch(); //处理请求context.setPre();context.setPre();context.setNext();}
}
结果如下:
当前档位是:低档位
当前是低档位,向前切换为中档位
当前是中档位,向前切换为高档位
当前是高档位,,向后切换为中档位
3.5 状态模式应用场景
- 当
一个对象的行为取决于它的状态
,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。即行为随状态改变而改变的场景,这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的行为结果也会不同,在这种情况下需要考虑使用状态模式。 - 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。
- 条件、分支判断语句的替代者。
注意:状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过 5 个。
四、观察者模式
4.1 观察者模式定义
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
在实际环境中,观察者常常和责任链模式一起使用,共同负责对事件的处理,其中某个观察者负责是否将事件进一步传递
。
在实际运用中,通知观察者的参数,往往可以封装成一个类,比如封装成一个事件(Event)
,示例:按键事件,从Event中往往可以获取到被观察者。
一句话总结:一个对象变化了,要通知到别的对象,以便处理这种变化。
4.2 观察者模式主要角色
观察者模式UML图示如下:
Subject类,抽象通知者(或主题),一个办用一个抽象类或一个接口实现。它把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者。主题中至少应包含三类方法:添加观察者、删除观察者和通知。
Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,重选ing观察者一般用一个抽象类或一个接口实现。
ConcreteSubject类,叫做具体主题或具体通知者,将有关状态存入具体观察者对象。在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题通常用一个具体子类实现。
ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的的更新接口,以便使本身的状态和主体的状态相协调。具体观察者角色通常用一个具体子类实现。
4.3 观察者模式特点
优点:
降低了目标与观察者之间的耦合
关系,两者之间是抽象耦合关系。- 目标与观察者之间建立了一套
触发
机制。
缺点:
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
观察者比较多,而且处理时间比较长,采用异步处理来考虑线程安全和队列的问题。
4.4 观察者模式实现方式
此处,以小明追小说为例,有两本小说《剑来》和《英雄志》都未完结,他关注了这两部小说,当则两部小说更新时,他都会收到对应的消息。代码示例如下:
/*抽象主题:小说*/
public abstract class Story {protected List<Observer> observers=new ArrayList<Observer>();//增加观察者方法public void add(Observer observer){observers.add(observer);} //删除观察者方法public void remove(Observer observer){observers.remove(observer);} public abstract void notifyObserver(int chapterNum); //通知观察者方法
}
/*具体主题1:剑来*/
public class Story1 extends Story{private String name = "jianlai";public void notifyObserver(int chapterNum){ for(Object obs:observers){((Observer)obs).response(this.name,chapterNum);}}
}
/*具体主题2:英雄志*/
public class Story2 extends Story{private String name = "yingxiongzhi";public void notifyObserver(int chapterNum){ for(Object obs:observers){((Observer)obs).response(this.name,chapterNum);}}
}
/*抽象观察者*/
public interface Observer {void response(String storyName,int number);
}
/*具体观察者:小明*/
public class ObserverXiaoming implements Observer{private String name = "小明";public void response(String storyName,int chapterNum) {if("jianlai".equals(storyName)){System.out.println("《剑来》更新了"+chapterNum+"章,"+this.name+"等养肥了在看");}else{System.out.println("《英雄志》更新了"+chapterNum+"章,"+this.name+"立马去看");}}
}
/*测试类*/
public class ObserverTest {public static void main(String[] args){Story story1=new Story1(); Story story2=new Story2(); Observer observer=new ObserverXiaoming(); story1.add(observer); story2.add(observer); story1.notifyObserver(20);story2.notifyObserver(10);}
}
示例结果如下:
《剑来》更新了20章,小明等养肥了在看
《英雄志》更新了10章,小明立马去看
4.5 观察者模式应用场景
- 对象间存在一对多关系,
一个对象的状态发生改变会影响其他对象
。 - 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列的处理机制。
五、备忘录模式
5.1 备忘录模式定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态
。该模式又叫快照
模式。
一句话总结:可以保存和撤销对象的行为。
5.2 备忘录模式主要角色
备忘录模式UML图示如下:
Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的哪些内部状态。
Memento(备忘录):负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象;Originator能看到一个宽接口,允许它返回到先前状态所需的所有数据。
Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。
注意:
- 备忘录的生命期;
- 备忘录的性能,不要在频繁建立备份的场景中使用备忘录模式(比如一个 for 循环中)。
5.3 备忘录模式特点
优点:
- 提供了一种
可以恢复状态
的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。 - 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
缺点:
- 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
5.4 备忘录模式实现方式
此处,以小亮周末做的一些事情为例,如:上午健身、下午和朋友聚餐、晚上看小说为例,用备忘录来记住他周末一天做的事,示例代码如下:
/*备忘录*/
public class Memento {private String state;public Memento(String state) {this.state = state;}public String getState() { return state; }
}
/*发起人:小亮*/
public class OriginatorXiaoliang {private String state;public String getState() { return state; }public void setState(String state) {this.state = state;}public Memento saveStateToMemento(){ return new Memento(state); }public void getStateFromMemento(Memento memento){state = memento.getState();}
}
/*管理者*/
public class CareTaker {private List<Memento> mementoList = new ArrayList<Memento>();public void add(Memento memento){mementoList.add(memento);}public Memento get(int index){ return mementoList.get(index); }
}
/*测试类*/
public class MementoTest {public static void main(String[] args) {OriginatorXiaoliang xiaoliang = new OriginatorXiaoliang();CareTaker careTaker = new CareTaker();xiaoliang.setState("健身");careTaker.add(xiaoliang.saveStateToMemento());xiaoliang.setState("和朋友聚会");careTaker.add(xiaoliang.saveStateToMemento());xiaoliang.setState("看小说");System.out.println("小亮晚上做的事: " + xiaoliang.getState());xiaoliang.getStateFromMemento(careTaker.get(0));System.out.println("小亮上午做的事: " + xiaoliang.getState());xiaoliang.getStateFromMemento(careTaker.get(1));System.out.println("小亮下午做的事: " + xiaoliang.getState());}
}
测试结果:
小亮晚上做的事: 看小说
小亮上午做的事: 健身
小亮下午做的事: 和朋友聚会
5.5 备忘录模式应用场景
- 需要
保存与恢复数据
的场景,如玩游戏时的中间结果的存档功能。 - 需要提供一个
可回滚操作
的场景,如Word、记事本、Photoshop,Eclipse等软件在编辑时按Ctrl+Z组合键,还有数据库中事务操作。 - 数据库连接的事务管理就是用的备忘录模式。
注意:
- 1、备忘录的生命期。
- 2、备忘录的性能。不要在频繁建立备份的场景中使用备忘录模式(比如一个 for 循环中)。
设计模式(四)行为型模式介绍及实例(上)相关推荐
- 设计模式(三)结构型模式介绍及实例
文章目录 一.适配器模式 1.1 适配器模式定义 1.2 适配器模式主要角色 1.3 适配器模式特点 1.4 适配器模式实现方式 1.4.1 类适配器模式 1.4.2 对象适配器模式 1.5 适配器模 ...
- java real football_Java学习--设计模式之行为型模式(三)
一.空对象模式(Null Object Pattern) 1.概念 在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查.Null 对象不是检查空值,而是 ...
- Java学习--设计模式之创建型模式
一.简介 创建型模式:这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象.这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活.创建型模式包括:工 ...
- 备战面试日记(3.2) - (设计模式.23种设计模式之创建型模式)
本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.6 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...
- 备战面试日记(3.4) - (设计模式.23种设计模式之行为型模式)
本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.12 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文 ...
- 设计模式_行为型模式学习
我们知道,创建型设计模式主要解决"对象的创建"问题,结构型设计模式主要解决"类或对象的组合或组装"问题,那行为型设计模式主要解决的就是"类或对象之间的 ...
- 设计模式之行为型模式(7种)
目录 一.模版方法模式(template ) 概念 模式中的角色 模板模式UML类图 案例 使用前 使用后 钩子函数应用场景 注意事项和细节 应用 优点 模板方法模式与开闭原则 二.命令模式 概念: ...
- java设计模式中不属于创建型模式_23种设计模式第二篇:java工厂模式定义:工厂模式是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式...
23种设计模式第二篇:java工厂模式 定义: 工厂模式是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 工厂模式主要是为创建对象提供过渡接口, ...
- 设计模式之创建型模式(工厂、原型、建造者)
文章目录 创建型模式 2.1 工厂设计模式 2.1.1 简单工厂模式 2.1.2 工厂方法模式 2.1.3 抽象工厂 2.1.4 工厂模式总结 2.1.5 Spring中的工厂模式 2.1.6 工作中 ...
最新文章
- 【转载】如何去除C#Strings中的空格?
- poj 3233 Matrix Power Series
- 计算机应用基础本科常见问题讨论,《计算机应用基础》(本科)2017年6月期末考试指导.pdf...
- 【CSON原创】HTML5字体动态粒子效果发布
- vue2.0关于添加属性后视图不能更新的问题
- jsp java乱码转换_JSP中文乱码问题《转》
- lnmp一键安装包删除添加的域名
- 昼猫笔记 JavaScript -- 闭包
- ASP.NET学习顺序(转摘)
- (翻译)UIP Application Block学习系列(三)UIP概念
- Linux 安全加固大全(合集)
- JS获取IP地址信息,以及设备信息
- 基于c语言的拉马努金法计算圆周率近似值
- Powerdesigner概念模型并将概念模型转换成物理模型
- 传感器实验——LCD显示小车状态
- mysql提交数据时会丢失一部分_技术|MYSQL数据丢失讨论
- 语音识别入门书籍推荐
- [建立基类Building,作为楼房类,这个基类中包含楼房层数、房间数、楼房总面积等。再建立派生类Home_Arch、Office_Building和Hospital,分别作为住宅楼类、办公楼类和医院
- 海华cywdhd wifi驱动移植
- 阿里云栖大会100位顶级大咖演讲PPT+视频全分享!