作者:Tom哥
公众号:微观技术
博客:https://offercome.cn
人生理念:知道的越多,不知道的越多,努力去学
面对复杂的业务场景,千变万化的客户需求,如何以一变应万变,以最小的开发成本快速落地实现,同时保证系统有着较低的复杂度,能够保证系统后续de持续迭代能力,让系统拥有较高的可扩展性。
这些是一个合格的架构师必须修炼的基础内功,但是如何修炼这门神功???
我将常用的软件设计模式,做了汇总,目录如下:
(考虑到内容篇幅较大,为了便于大家阅读,将软件设计模式系列(共23个)拆分成四篇文章,每篇文章讲解六个设计模式,采用不同的颜色区分,便于快速消化记忆)
前文回顾:
本文是主要讲解桥接模式
、组合模式
、装饰模式
、门面模式
、代理模式
、责任链模式
自然界一般由实体和行为组成。当然为了提升系统的扩展性,它们两个又可以各自抽象,然后在抽象类中描述两者的依赖。
定义:
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
什么场景使用桥接模式?
核心思路:
代码示例:
/**
* @author 微信公众号:微观技术
* 抽象实体
*/
public abstract class AbstractEntity {
protected AbstractBehavior abstractBehavior;
public AbstractEntity(AbstractBehavior abstractBehavior) {
this.abstractBehavior = abstractBehavior;
}
public abstract void out();
}
/**
* 抽象行为
*/
public interface AbstractBehavior {
public String action(String name);
}
/**
* 关于食物的行为
*/
public class FoodBehavior implements AbstractBehavior {
@Override
public String action(String name) {
if ("中国人".equals(name)) {
return "吃 饺子";
} else if ("美国人".equals(name)) {
return "吃 汉堡";
}
return null;
}
}
桥接模式是将抽象与抽象之间分离,具体实现类依赖于抽象。抽象的分离间接完成了具体类与具体类之间的解耦,它们之间使用抽象来进行组合或聚合,而不再靠多重继承来实现。本质是将一个对象的实体和行为分离,然后再基于这两个维度进行独立的演化。
适用场景:
定义:
组合模式也称整体模式,把一组相似的对象当作一个单一的对象,然后将对象组合成
树形结构
以表示整个层次结构。
这里边有两个关键点:1、树形结构分层 2、业务统一化来简化操作
核心思路:
代码示例:
public abstract class AbstractNode {
public abstract void add(AbstractNode abstractNode);
public abstract void remove(AbstractNode abstractNode);
public abstract void action();
}
public class CompositeNode extends AbstractNode {
private Long nodeId;
private List<AbstractNode> childNodes; //存放子节点列表
public CompositeNode(Long nodeId, List<AbstractNode> childNodes) {
this.nodeId = nodeId;
this.childNodes = childNodes;
}
@Override
public void add(AbstractNode abstractNode) {
childNodes.add(abstractNode);
}
@Override
public void remove(AbstractNode abstractNode) {
childNodes.remove(abstractNode);
}
@Override
public void action() {
for (AbstractNode childNode : childNodes) {
childNode.action();
}
}
}
public class LeafNode extends AbstractNode {
private Long nodeId;
public LeafNode(Long nodeId) {
this.nodeId = nodeId;
}
@Override
public void add(AbstractNode abstractNode) {
// 无子节点,无需处理
return;
}
@Override
public void remove(AbstractNode abstractNode) {
// 无子节点,无需处理
return;
}
@Override
public void action() {
System.out.println("叶子节点编号:" + nodeId);
}
}
叶子节点不能新增、删除子节点,所以对应的方法为空。
组合模式本质上封装了复杂结构的内在变化,让使用者通过一个统一的整体来使用对象之间的结构。数据结构方面支持树形结构
、环形结构
、网状结构
。如我们常见的 深度优先搜索
、广度优先搜索
都是采用这种模式。
适用场景:
手机开始是按品牌来归属分类,现在业务增加价格维度分类,我们只需要引入新的分支节点,按新的维度构建组合关系。
定义:
动态地向一个现有对象添加新的职责和行为,同时又不改变其结构,相当于对现有的对象进行包装。
核心思路:
代码示例:
public abstract class Component {
public abstract void execute();
}
public class ConcreteComponent extends Component {
@Override
public void execute() {
System.out.println("具体子类 ConcreteComponent invoke !");
}
}
public class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void execute() {
component.execute();
}
}
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void execute() {
System.out.println("装饰器子类 ConcreteDecorator invoke !");
super.execute();
}
}
装饰模式本质上就是给已有不可修改的类附加新的功能,同时还能很方便地撤销。
适用场景:
final
关键字限制了某个类的进一步扩展,可以通过装饰器对其进行封装,从而具备扩展能力。定义:
门面模式提供一个高层次的接口,要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,使得子系统更易于使用。
门面模式要求我们使用统一的标准与系统交互,比如:我们打印日志基本会选择slf4j
框架,其内部统一了log4j
、log4j2
、CommonLog
等日志框架,简化了我们的开发成本。
核心思路:
简单来讲,引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口。
可能很多人有疑问,这个不就是代理模式吗?
门面模式可能代理的是多个接口,而代理模式通常只是代理一个接口。
业务场景:
移动互联网,我们都习惯了在线支付,相信很多人在付款时都听过这么一句话,”微信支付还是支付宝“,商户根据用户反馈再针对性选择收款渠道。
是不是很繁琐,为了解决这个问题,市面就有了聚合支付(该领域做非常棒的是收钱吧),整个业务模式就是这节要讲的门面模式,不管你用什么软件支付,只要打开付款二维码即可,收钱吧底层识别解析二维码,并根据扫描结果自动适配对应的收款渠道,完成用户的扣款动作,确实带来不错的用户体验。
优点:
JPA
提供了统一Java持久层API,底层适配多样化的存储系统。SPI架构
一样,支持水平扩展。定义:
为其他对象提供一种代理以控制对这个对象的访问
现实场景:
核心思路:
抽象主题类
的接口方法抽象主题类
的接口方法,内部包含主题实现类
的逻辑, 同时还包含一些自身的扩展操作。代理模式与适配器模式相似。但适配器模式是转换为新的接口,而代理模式不会改变原有接口。
代码示例:
/**
* @author 微信公众号:微观技术
*/
public interface AbstractSubject {
void execute();
}
public class RealSubject implements AbstractSubject {
@Override
public void execute() {
System.out.println("我是Tom哥,我要努力工作!");
}
}
public class Proxy implements AbstractSubject {
private AbstractSubject abstractSubject;
public Proxy(AbstractSubject abstractSubject) {
this.abstractSubject = abstractSubject;
}
@Override
public void execute() {
System.out.println("老板给Tom哥分配工作了。。。");
abstractSubject.execute();
}
}
按使用职责分为静态代理和动态代理。
优点:
适用场景:
定义:
责任链模式是一种行为设计模式,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链。收到请求后,每个处理者均可对请求进行处理,或将其传递给链中的下个处理者。
责任链模式是对数据结构中的链表
结构的具体应用。
核心思路:
抽象处理者
的实现子类,判断本次请求是否处理,如果需要则处理,否则跳过,然后将请求转发给下一个节点。优点:
像我们常见的网关架构推荐使用该模式,通过服务编排,可以自由地在任意位置添加或移除节点,满足一系列个性化功能。
设计模式很多人都学习过,但项目实战时总是晕晕乎乎,原因在于没有了解其核心是什么,底层逻辑是什么,《设计模式:可复用面向对象的基础》有讲过,
在设计中思考什么应该变化,并封装会发生变化的概念。
软件架构的精髓:找到变化,封装变化。
业务千变万化,没有固定的编码答案,千万不要硬套设计模式。无论选择哪一种设计模式,尽量要能满足SOLID
原则,自我review是否满足业务的持续扩展性。有句话说的好,“不论白猫黑猫,能抓老鼠就是好猫。”