设计模式是什么?
设计模式是软件设计中常见问题的典型解决方案。他们就像能根据需求调整的预制蓝图,可用于解决代码中反复出现的设计问题。
他和算法有些类似,但是却又不完全相同。
如果把程序员比作厨子的话,那算法就好比菜谱,他详细的描述了从头到尾的步骤,只需要厨子按图索骥就好。而设计模式就好比菜系,厨子只知道结果是什么,但详细步骤得自己实现。
优缺点
设计模式是定义了一种团队能够高效沟通的通用语言,你只需要说:“哦,这里用单例就可以实现了”,这时团队的大部分人都会理解你的意思,而不需要你在解释什么是单例。
如果你只有一把铁锤,那么房间里的任何东西看上去都是钉子。
有趣的是,在学习了设计模式之后,你会发现我们写的代码中处处能用到这个模式,比如策略模式可以简单的使用 lambda 函数来实现。这也会给初学者带来很大的困扰
原则
- 单一职责(一个类和方法只做一件事)
- 里氏替换(多态,子类在扩展父类)
- 依赖倒置(细节依赖抽象,下层依赖上层)
- 接口隔离(建立单一接口)
- 迪米特原则 (最少知道,降低耦合)
- 开闭原则 (在实现新功能时保持已有代码不变,==抽象架构,扩展实现==)
分类
- 创建型模式
这类模式提供创建对象的机制,能够提升已有代码的灵活性和可复用性
| 序号 | 类型 | 解析图 | 举例说明 | 实现要点 |
|---|---|---|---|---|
| 1 | 工厂方法 | 手机是一个抽象产品,而小米,华为,苹果是具体的产品实现,而不同牌的手机在各自的生产厂家中生产 | 定义一个创建对象的接口,让子类自己决定实例化哪一个工厂类,使创建过程延迟到子类进行 | |
| 2 | 抽象工厂 | 华为和苹果都有手机,耳机,手环等业务。但是华为工厂只会生产华为系列品牌,相对应的苹果也相同。(替换Redis双集群升级,代理类抽象场景) | 定义一系列相关或者相互依赖对象的接口,放入不同抽象工厂中,而不需要指定他们具体的类 | |
| 3 | 建造者 | 台式电脑由显卡,主机,硬盘,内存等组件组装而成,但每个组件也有不同型号,选择套餐 | 将一个复杂的构建拆分,使得同样的过程可以创建不同的对象 | |
| 4 | 原型 | 软考,考生题目和答案实现乱排序 | 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 | |
| 5 | 单例 | 只有一片雪花 | 保证一个类仅有一个实例,并提供一个访问它的方法 |
- 结构型模式
这类模式介绍如何将对象和类组装成较大的结构,并同时保持结构的灵活和高效
| 序号 | 类型 | 解析图 | 举例说明 | 实现要点 |
|---|---|---|---|---|
| 1 | 适配器 | 扩展坞功能 | 将一个类的接口转换为客户希望的另外一个接口,适配器模式使得原本接口不兼容的类可以一起工作 | |
| 2 | 桥接 | 多支付渠道(微信、支付宝)以及多支付模式(指纹、密码)等 | 将一个大类或一系列紧密的类拆分为抽象和实现两个独立的层次,从而在开发时分别使用 | |
| 3 | 组合 | 获取各大省份和城市信息 | 将对象组合成树状结构用来表示 “部分-整体”的层次结构。对于使用单个对象还是组合对象的使用具有一致性 | |
| 4 | 装饰 | SSO单点登录扩展拦截用户(HttpServletRequest 修改token) | 动态的为一个对象添加一些功能。仅增加一些功能时,装饰器模式相比于子类更灵活,也更易于维护 | |
| 5 | 外观 | 类似于网关,统一控制接口分发,但不关注于内部实现 | 定义了一个高层接口,为框架和复杂类提供了一个简单的入口,因此又称门面模式 | |
| 6 | 享元 | Redis秒杀场景,提供了活动与库存信息查询 | 适用于需要管理大量细粒度对象、希望减少内存占用并提高性能的情况下 | |
| 7 | 代理 | 类似于 AOP(如Mybatis定义DAO接口) | 让你能够提供对象的替代品或者占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理 |
- 行为模式
这类模式负责对象间的高效沟通和职责委派
| 序号 | 类型 | 解析图 | 举例说明 | 实现要点 |
|---|---|---|---|---|
| 1 | 责任链 | 钉钉OA审批 | 避免消费者和生产者耦合在一起,允许每个对象都可以处理请求,或将其传递给下一个链式的处理者 | |
| 2 | 命令 | 小二点单厨师炒菜 | 定义一个对象,从而使你可以用不同的请求对客户进行操作,并且允许撤销请求 | |
| 3 | 迭代器 | 遍历集合信息 | 在你无需暴露对象内部结构的情况下遍历集合中所有的元素 | |
| 4 | 中介者模式 | Mybatis相比于JDBC的改进 | 用一个对象封装一系列的对象交互,减少了对象之间混乱无序的依赖关系。迫使其他对象只能和中介者合作。 | |
| 5 | 备忘录 | 配置文件回滚 | 在不暴露对象实现细节的情况下保存和恢复之前的状态 | |
| 6 | 观察者 | undoLog,redoLog文件 | 定义对象间一对多的依赖关系,当对象状态改变时,所有依赖于它的对象都得到通知并且自动更新 | |
| 7 | 状态 | 掘金的文章状态(审核,草稿,发布) | 允许对象在内部状态发生改变时,对象看起来好像修改了它的类 | |
| 8 | 策略 | 商品的多种优惠方案 | 定义一系列的算法,把他们单独封装起来,并且允许互相替换 | |
| 9 | 模板方法 | 一个模板对应多个商品生成海报 | 定义一个骨架类,将其中步骤延迟到子类中。这样可以使得子类在不修改结构的情况下重写特定步骤 | |
| 10 | 访问者 | 给不同的客户推销不同的保险 | 将数据结构和数据操作分离 |
参考资料
逼逼叨叨
各位好呀,我是小羊。
年后复工疯狂加班,终于赶在截止时间内上线新系统。本以为终于可以偷的几日闲了,结果客户反馈一堆问题上来。
我记得我全按照产品原型来写流程的呀,怎么会一堆流程问题呢?当时我就手握一根“棒球棍”,右拿一把“开 山刀”,准备去产品部好好沟通沟通,是不是你小子给我下套了。
“小羊,我说我也不知道流程是什么你信吗?”
“你猜我信吗?”
“一顿烧烤信不信”
“好吧,我听你给我狡辩”
这不是我贪图这一顿烧烤,而是大家都是为老板卖命的,没必要拼的你死我活嘛,团结就是这样。就这样,在产品的说明下,我才明白这是怎么一回事。
你猜怎么着?
这次新系统原型和业务流程都没有经过客户确认的。本来产品打算和客户好好沟通需求的,架不住“上面”催的急,下了死命令,说你就按照现有的给他搞一套新的就好了,这有什么问题?
这下子产品也没办法了,他说这是甲鱼的臀部-规定,只能硬着头皮画了个原型,写了份需求给我们开发。
啊,朋友们,小羊当时心都是绝望的。你怎么啷个样子哦,真是老母猪戴胸罩,一套又一套的。
但是在修复问题的过程中,才发现设计模式的重要,好的设计并不需要改动太多就能完成自己的需求,不像我这样子嘎嘎乱改,耽误了太多时间去重构代码,因此打算来重读一下设计模式。