愿景:"让编程不再难学,让技术与生活更加有趣"
更多架构课程请访问 xdclass.net
目录
第3集 JDK源码里面的Stream IO流-装饰器设计模式应用
第6集 大量使用第三方SDK-它们常用的外观设计模式你知道多少?
第8集 Flyweight Pattern享元设计模式你知道多少
简介:讲解-装饰器设计模式介绍和应用场景
-
装饰器设计模式(Decorator Pattern)
- 也叫包装设计模式,属于结构型模式,它是作为现有的类的一个包装,允许向一个现有的对象添加新的功能,同时又不改变其结构
- 给对象增加功能,一般两种方式 继承或关联组合,将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为来增强功能,这个就是装饰器模式,比继承模式更加灵活
-
应用场景
-
小滴课堂-老王,本来计划买跑车撩妹的,结果口袋没钱,改买自行车,为了显得突出,店家提供多种改装方案,加个大的喇叭、加个防爆胎等,经过装饰之后成为目的更明确的自行车,更能解决问题。像这种不断为对象添加装饰的模式就叫 Decorator 模式,Decorator 指的是装饰物。
-
以动态、透明的方式给单个对象添加职责,但又能不改变其结构
-
JDK源码里面应用的最多的就是IO流,大量使用装饰设计模式
-
-
角色(装饰者和被装饰者有相同的超类(Component))
-
抽象组件(Component)
- 定义装饰方法的规范,最初的自行车,仅仅定义了自行车的API;
-
被装饰者(ConcreteComponent)
- Component的具体实现,也就是我们要装饰的具体对象
- 实现了核心角色的具体自行车
-
装饰者组件(Decorator)
-
定义具体装饰者的行为规范, 和Component角色有相同的接口,持有组件(Component)对象的实例引用
-
自行车组件 都有 名称和价格
-
-
具体装饰物(ConcreteDecorator)
- 负责给构件对象装饰附加的功能
- 比如 喇叭,防爆胎
-
第2集 满足老王的改装搭配-玩转装饰器设计模式案例实战
简介:装饰器设计模式案例实战
- 背景需求
小滴课堂-老王,由于公司发了项目奖金,不够买跑车,就先买自行车,店家里面 有小号、中号、大号等规格的自行车。
然后改造加一个喇叭,后来不够又要加多一个,一个防爆胎不够,又有两个,存在很多个随机组合的改装。
店家就苦恼了,这样的结构难搞,价格也难算,而且需求再变动,就更麻烦了。
使用装饰者就可以解决这个问题
- 不采用设计模式,你会怎么做?自己试试,然后看是否够灵活
- 采用装饰器设计模式编码实战
-
优点
- 装饰模式与继承关系的目的都是要扩展对象的功能,但装饰模式可以提供比继承更多的灵活性。
- 使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,原有代码无须改变,符合“开闭原则”
-
缺点
- 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂 (多层包装)
- 增加系统的复杂度,加大学习与理解的难度
-
装饰器模式和桥接模式对比
-
相同点都是通过封装其他对象达到设计的目的,和对象适配器也类似,有时也叫半装饰设计模式
-
没有装饰者和被装饰者的主次区别,桥接和被桥接者是平等的,桥接可以互换,不用继承自同一个父类
比如例子里面的,可以是Phone持有Color,也可以是Color持有Phone
-
桥接模式不用使用同一个接口;装饰模式用同一个接口装饰,接口在父类中定义
-
第3集 JDK源码里面的Stream IO流-装饰器设计模式应用
简介:讲解-装饰器设计模式在JDK源码里面应用场景
-
抽象组件(Component):InputStream
- 定义装饰方法的规范
-
被装饰者(ConcreteComponent) : FileInputStream 、ByteArrayInputStream
- Component的具体实现,也就是我们要装饰的具体对象
-
装饰者组件(Decorator):FilterInputStream
- 定义具体装饰者的行为规范, 和Component角色有相同的接口,持有组件(Component)对象的实例引用
- 自行车组件 都有 名称和价格
-
具体装饰物(ConcreteDecorator):BufferedInputStream、DataInputStream
- 负责给构件对象装饰附加的功能
- 比如 喇叭,防爆胎
- 应用场景
//添加了Buffer缓冲功能
InputStream inputStream = new BufferedInputStream(new FileInputStream(""));
第4集 加盟商来啦-你需要掌握的代理设计模式《上》
简介:讲解代理设计模式,让代理帮你完成工作《上》
-
代理设计模式(Proxy Pattern)
-
为其他对象提供一种代理以控制对这个对象的访问,属于结构型模式。
-
客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象
-
-
应用场景
- 各大数码专营店,代理厂商进行销售对应的产品,代理商持有真正的授权代理书
- 客户端不想直接访问实际的对象,或者访问实际的对象存在困难,通过一个代理对象来完成间接的访问
- 想在访问一个类时做一些控制,或者增强功能
-
角色
- Subject: 抽象接口,真实对象和代理对象都要实现的一个抽象接口,好比销售数码产品
- Proxy: 包含了对真实对象的引用,从而可以随意的操作真实对象的方法,好比 代理加盟店
- RealProject :真实对象,好比厂商销售数码产品
第5集 加盟商来啦-你需要掌握的代理设计模式《下》
简介:讲解代理设计模式,让代理帮你完成工作《下》
- 业务需求
小滴课堂-老王,想开个数码小卖部,为以后退休生活做准备,代理各大厂商的手机和电脑,用代理设计模式帮他实现下
Subject 卖手机
RealProject 苹果、华为厂商,核心是卖手机,但是选址不熟悉
Proxy 老王数码专卖店:代理卖手机,附加选地址,增加广告等
编码实战
/**
* 抽取公共的方法
*/
public interface DigitalSell {
void sell();
}
/**
* 小滴课堂,愿景:让技术不再难学
*
* @Description 真实的对象
* @Author 二当家小D
* @Remark 有问题直接联系我,源码-笔记-技术交流群
* @Version 1.0
**/
public class DigitalSellReal implements DigitalSell{
@Override
public void sell() {
System.out.println("销售华为手机");
}
}
/**
* 小滴课堂,愿景:让技术不再难学 https://xdclass.net
*
* @Description 代理对象,增加了功能
* @Author 二当家小D
* @Remark 有问题直接联系我,源码-笔记-技术交流群 微信 xdclass6
* @Version 1.0
**/
public class DigitalSellProxy implements DigitalSell {
private DigitalSell realObj = new DigitalSellReal();
@Override
public void sell() {
makeAddress();
realObj.sell();
makeAD();
}
private void makeAddress(){
System.out.println("一个人流量很高的地址");
}
private void makeAD(){
System.out.println("投放广告");
}
}
//使用
public static void main(String[] args) {
//真实对象的行为
DigitalSell realObj = new DigitalSellReal();
realObj.sell();
//代理对象的行为
DigitalSell proxy = new DigitalSellProxy();
proxy.sell();
}
-
优点
- 可以在访问一个类时做一些控制,或增加功能
- 操作代理类无须修改原本的源代码,符合开闭原则,系统具有较好的灵活性和可扩展性
-
缺点
- 增加系统复杂性和调用链路
-
有静态代理和动态代理两种
- 动态代理也有多种方式,cglib、jdk,可以看看新版Springboot专题的spring5模块
-
和装饰器模式的区别:
-
代理模式主要是两个功能
- 保护目标对象
- 增强目标对象,和装饰模式类似了
-
第6集 大量使用第三方SDK-它们常用的外观设计模式你知道多少?
简介:讲解外观设计模式的介绍和应用场景
-
外观设计模式 Facade Pattern
- 门面模式,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口
- 定义了一个高层接口,这个接口使得这系统更加容易使用
-
应用场景
- 在外人看来,小滴课堂-老王是负责消息推送这个工作,看起来很轻松,但他们不知道里面有多复杂,老王加班多久才输出一个统一的接口,只要轻松操作就可以完成复杂的事情
- 开发里面MVC三层架构,在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间使用interface接口进行交互,不用担心内部逻辑,降低耦合性
- 各种第三方SDK大多会使用外观模式,通过一个外观类,也就是整个系统的接口只有一个统一的高层接口,这对用户屏蔽很多实现细节,外观模式经常用在封装API的常用手段
- 对于复杂难以维护的老系统进行拓展,可以使用外观设计模式
- 需要对一个复杂的模块或子系统提供一个外界访问的接口,外界对子系统的访问只要黑盒操作
-
角色
- 外观角色(Facade):客户端可以调用这个角色的方法,这个外观方法知道多个子系统的功能和实际调用
- 子系统角色(SubSystem):每个子系统都可以被客户端直接调用,子系统并不知道门面的存在,
第7集 案例实战-外观设计模式在多渠道消息推送里面的应用
简介:讲解外观设计模式的案例实战
- 业务需求
在外人看来,小滴课堂-老王是负责消息推送这个工作,看起来很轻松,但他们不知道里面有多复杂
需要对接微信消息、邮件消息、钉钉消息等,老王加班长期加班没有女友,才输出一个统一的接口,只要轻松操作就可以完成复杂的事情
用外观设计模式帮老王完成这个需求
-
优点
-
减少了系统的相互依赖,提高了灵活性
-
符合依赖倒转原则
- 针对接口编程,依赖于抽象而不依赖于具体
-
符合迪米特法则
- 最少知道原则,一个实体应当尽量少地与其他实体之间发生相互作用
-
-
缺点
- 增加了系统的类和链路
- 不是很符合开闭原则,如果增加了新的逻辑,需要修改facade外观类
第8集 Flyweight Pattern享元设计模式你知道多少
简介:讲解享元设计模式的介绍和应用场景
-
享元设计模式(Flyweight Pattern)
- 属于结构型模式,主要用于减少创建对象的数量,以减少内存占用和提高性能, 它提供了减少对象数量从而改善应用所需的对象结构的方式。
- 享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象
-
应用场景
- JAVA 中的 String,如果字符串常量池里有则返回,如果没有则创建一个字符串保存在字符串常量池里面
- 数据库连接池、线程池等
- 如果系统有大量相似对象,或者需要用需要缓冲池的时候可以使用享元设计模式,也就是大家说的池化技术
- 如果发现某个对象的生成了大量细粒度的实例,并且这些实例除了几个参数外基本是相同的,如果把那些共享参数移到类外面,在方法调用时将他们传递进来,就可以通过共享对象,减少实例的个数
-
内部状态
- 不会随环境的改变而有所不同,是可以共享的
-
外部状态
- 不可以共享的,它随环境的改变而改变的,因此外部状态是由客户端来保持(因为环境的变化一般是由客户端引起的)
-
角色
- 抽象享元角色:为具体享元角色规定了必须实现的方法,而外部状态就是以参数的形式通过此方法传入
- 具体享元角色:实现抽象角色规定的方法。如果存在内部状态,就负责为内部状态提供存储空间。
- 享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键
- 客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外部状态
第9集 老王接网站外包-享元设计模式案例实战和优缺点
简介:讲解享元设计模式的案例实战和优缺点
- 案例实战
小滴课堂-老王为了增加收入,开始接了外包项目,开发了一个AI网站模板,可以根据不同的客户需求自动生成不同类型的网站
电商类、企业产品展示、信息流等。
在部署的时候就麻烦了,是不是每个机器都用租用云服务器,购买独立域名呢
这些网站结构相似度很高,而且都不是高访问量网站,可以先公用服务器资源,减少服务器资源成本,类似虚拟机或者Docker
public class Company {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Company(){}
public Company(String name){
this.name = name;
}
}
//抽象接口,
public abstract class CloudWebSite {
public abstract void run(Company company);
}
/**
* 小滴课堂,愿景:让技术不再难学 https://xdclass.net
*
* @Description
* @Author 二当家小D
* @Remark 有问题直接联系我,源码-笔记-技术交流群 微信 xdclass6
* @Version 1.0
**/
public class ConcreteWebSite extends CloudWebSite {
private String category;
public ConcreteWebSite(String category){
this.category = category;
}
@Override
public void run(Company company) {
System.out.println("网站分类:"+category+", 公司:"+company.getName());
}
}
//工厂
public class WebSiteFactory {
/**
* map里面的key是分类
*/
private Map<String,ConcreteWebSite> map = new HashMap<>();
/**
* 根据key获取分类站点
* @param category
* @return
*/
public CloudWebSite getWebSiteByCategory(String category){
if(map.containsKey(category)){
return map.get(category);
}else {
ConcreteWebSite site = new ConcreteWebSite(category);
map.put(category,site);
return site;
}
}
/**
* 获取分类个数
* @return
*/
public int getWebsiteCategorySize(){
return map.size();
}
}
//使用
public static void main(String[] args) {
WebSiteFactory factory = new WebSiteFactory();
CloudWebSite companySite1 = factory.getWebSiteByCategory("企业官网");
companySite1.run(new Company("小滴课堂"));
CloudWebSite companySite2 = factory.getWebSiteByCategory("企业官网");
companySite2.run(new Company("旭瑶课堂"));
CloudWebSite byteDanceSite = factory.getWebSiteByCategory("信息流");
byteDanceSite.run(new Company("字节跳动"));
CloudWebSite ucNews = factory.getWebSiteByCategory("信息流");
ucNews.run(new Company("优视科技"));
System.out.println("网站分类总数:" +factory.getWebsiteCategorySize());
}
-
优点
- 大大减少了对象的创建,降低了程序内存的占用,提高效率
-
缺点
- 提高了系统的复杂度,需要分离出内部状态和外部状态
- 注意划分内部状态和外部状态,否则可能会引起线程安全问题,必须有一个工厂类加以控制
-
享元设计模式和原型、单例模式的区别
- 原型设计模式是指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
- 单例设计模式保证一个类仅有一个实例
干货文档