设计模式

1 阅读9分钟

结构型模式

适配器模式

  1. 适用场景:需要用到一个已经存在的类或接口,而它的定义和当前需要的接口定义不一样

  2. 对于底层依赖,主动增加适配器(防腐层),可以隔离底层的变动

代理模式

  1. 代理类、目标类

  2. 常用场景:

    1. 系统权限控制:SSO

    2. mapi

    3. spring AOP动态代理

  3. 控制逻辑做改造,不会影响到核心的业务逻辑

  4. 适用场景:

    1. 对目标的访问行为加一层控制和拦截

    2. 优点是将控制逻辑和主业务逻辑隔离

装饰器模式

  1. 在一个操作的基础上,增加一个或多个操作

  2. 需要为现有对象增加额外的职责,需要动态附加几个职责

    public class Main {
        public interface Dao {
            void issue(String data);
        }
    
        public static class OriginalCouponDao implements Dao {
            @Override
            public void issue(String data) {
                System.out.println("原始数据存储");
            }
        }
    
        public static class DecoratorDao implements Dao {
            private Dao decorator;
            public DecoratorDao(Dao decorator) {
                this.decorator = decorator;
            }
            @Override
            public void issue(String data) {
                decorator.issue(data);
            }
        }
    
        public static class TargetCouponDao extends DecoratorDao {
            private Dao decorator;
            public TargetCouponDao(Dao decorator) {
                super(decorator);
            }
            @Override
            public void issue(String data) {
                super.issue(data);
                System.out.println("新数据库写入数据:" + data);
            }
        }
    
        public static class SyncCouponInfo extends DecoratorDao {
            public SyncCouponInfo(Dao decorator) {
                super(decorator);
            }
            @Override
            public void issue(String data) {
                super.issue(data);
                System.out.println("数据同步给其他业务方:" + data);
            }
        }
    
        public static void main(String[] args) {
            Dao originalCouponDao = new OriginalCouponDao(); // 一个类实现interface
            originalCouponDao.issue("领第一张券");
    
            Dao targetCouponDao = new TargetCouponDao(originalCouponDao); // 两个类,各自重写对应方法,实现多态
            targetCouponDao.issue("领第二张券");
    
            Dao syncCouponInfo = new SyncCouponInfo(originalCouponDao);
            syncCouponInfo.issue("领第三张券");
        }
    }
    

代理和装饰器模式的对比

  1. 目的不同:代理是控制,装饰是附加

  2. 实现有区别:代理就一层,装饰器一般会嵌套好几层

  3. 代理不要求同源,装饰器模式一般要求同源(原始对象的继承)

  4. 客户端不能访问被代理类,代理类决定被代理对象是什么;装饰对象可以被访问,客户端决定装饰哪个对象

组合模式

如何实现无穷嵌套的对象

常用场景

  1. 多级菜单

  2. 文件系统

  3. 组织架构

    1. 部门、部门的人

    import java.util.ArrayList; import java.util.List;

    public class Main { public static abstract class TeamComponent { // 统一接口,抽象类 protected String name;

        protected List<TeamComponent> teamComponents = new ArrayList<>();
    
        public TeamComponent(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        abstract void walkThrough(String levelDeep); // 抽象函数(纯虚函数,子类必须实现该方法)
    
        abstract void addComponent(TeamComponent teamComponent);
    }
    public static class Member extends TeamComponent { // 叶子节点
        public Member(String name) {
            super(name);
        }
        @Override
        void walkThrough(String levelDeep) {
            System.out.println(levelDeep + this.name);
        }
        @Override
        void addComponent(TeamComponent teamComponent) {
            System.out.println("错误:不能给成员添加元素");
        }
    }
    public static class Team extends TeamComponent { // 组节点
        public Team(String name) {
            super(name);
        }
    
        @Override
        void walkThrough(String levelDeep) {
            System.out.println(levelDeep + this.name);
            List<TeamComponent> teamComponentsOnCurrentLevel = new ArrayList<>();
            for (TeamComponent teamComponent : this.teamComponents) {
                if (teamComponent instanceof Member) {
                    teamComponent.walkThrough(levelDeep + "-");
                } else if (teamComponent instanceof Team) {
                    teamComponentsOnCurrentLevel.add(teamComponent);
                }
            }
            if (teamComponentsOnCurrentLevel.size() > 0) {
                for (TeamComponent teamComponent : teamComponentsOnCurrentLevel) {
                    teamComponent.walkThrough(levelDeep + "-");
                }
            }
        }
    
        @Override
        void addComponent(TeamComponent teamComponent) {
            teamComponents.add(teamComponent);
            System.out.println(this.name + "增加了元素" + teamComponent.getName());
        }
    }
    
    public static Team buildTeam(String teamName, List<String> memberNames) {
        Team team = new Team(teamName);
        for (String memberName : memberNames) {
            Member member = new Member(memberName);
            team.addComponent(member);
        }
        return team;
    }
    
    public static void main(String[] args) {
        Member director = new Member("部门总监");
        List<String> members = new ArrayList<>();
        members.add("组员1");
        members.add("组员2");
        members.add("组员3");
        Team techTeam1 = buildTeam("技术组1", members);
        Team techTeam2 = buildTeam("技术组2", members);
        Team bg = new Team("技术部门");
        bg.addComponent(techTeam1);
        bg.addComponent(techTeam2);
        bg.addComponent(director);
        bg.walkThrough("-");
    }
    

    }

适用场景

  1. 需要表示多个对象,对象之间互相有嵌套关系,嵌套关系层级不定

  2. 不管哪一层级,对象包含的方法都是一样的

  3. 需要能通过递归遍历所有对象

门面模式

常用场景

  1. 支付服务

  2. 风控服务

    //TIP 要运行代码,请按 或 // 点击装订区域中的 图标。

    import java.util.ArrayList; import java.util.List;

    public class Main { public static class UserContext { private int userId; private int couponId; public UserContext(int userId,int couponId) { this.userId = userId; this.couponId = couponId; } public int getUserId() { return userId; } public int getCouponId() { return couponId; } }

    public static class CouponAccountService { // 账户子系统
        public void issue(UserContext userContext) {
            System.out.println("给用户" + userContext.getUserId() + "发券:" + userContext.getCouponId());
        }
    }
    
    public static class StockService { // 库存子系统
        public void checkStock(UserContext userContext) {
            System.out.println("检查券库存:" + userContext.getCouponId());
        }
        public void lockStock(UserContext userContext) {
            System.out.println("锁定券库存:" + userContext.getCouponId());
        }
        public void updateStock(UserContext userContext) {
            System.out.println("更新券库存信息:" + userContext.getCouponId());
        }
    }
    
    public static class RuleService { // 规则子系统
        public void checkRule(UserContext userContext) {
            System.out.println("根据规则检查券的有效性:" + userContext.getCouponId());
        }
    }
    
    public static class NoticeService { // 通知子系统
        public void sendNotice(UserContext userContext) {
            System.out.println("给用户" + userContext.getUserId() + "发PUSH:恭喜你获得了券" + userContext.getCouponId());
        }
    }
    
    public static class CouponFacadeService { // 门面类,把几个系统封装起来
        private CouponAccountService couponAccountService;
        private StockService stockService;
        private RuleService ruleService;
        private NoticeService noticeService;
        public CouponFacadeService() {
            this.couponAccountService = new CouponAccountService();
            this.stockService = new StockService();
            this.ruleService = new RuleService();
            this.noticeService = new NoticeService();
        }
        public void issue(UserContext userContext) {
            stockService.checkStock(userContext);
            stockService.lockStock(userContext);
            stockService.updateStock(userContext);
            ruleService.checkRule(userContext);
            this.couponAccountService.issue(userContext);
            noticeService.sendNotice(userContext);
        }
        public void doIssue(UserContext userContext) {
    
        }
    }
    
    public static void main(String[] args) {
        CouponFacadeService couponFacadeService = new CouponFacadeService();
        UserContext userContext = new UserContext(10000,1);
        couponFacadeService.issue(userContext);
    }
    

    }

适用场景

  1. 某一服务或流程内部逻辑特别复杂,且外部不需要知道实现细节

  2. 客户端和服务端耦合严重

  3. 分层系统架构设计,每层逻辑会对底层逻辑封装

桥接模式

享元模式

创建型模式

工厂模式(工厂三剑客)

  1. 对象创建和使用分离,达到解耦的目的

  2. 封装对象的创建过程,屏蔽未来创建过程可能的变化

简单工厂模式(一个类,一堆方法switch)

适用场景

  1. 需要创建的对象比较少

  2. 客户端不用关心创建过程

  3. 工程中的业务逻辑不会太复杂(创建的过程比较简单,类比较少,比较小)

    @Repository public class AccountOpFactory { // 简单工厂类 /** * 创建账户操作OP * * @param instructionSet * @param account * @return */

    public AccountOp createAccountingOp(AccoutingInstructionSet instructionSet, Account account) {
        RequestType requestType = RequestType.findByValue(instructionSet.getRequestType());
        assertRequestType(requestType);
    
        switch (requestType) {
            case UK_UNFREEZE_DEC:
                return new InnerUnfreezeDecOp(account, instructionSet, accountDetailRepository, freezeDetailRepository);
            case UNFREEZE_DEC:
                return new UnfreezeDecop(account, instructionSet, accountDetailRepository, freezeDetailRepository);
            case FREEZE_INC:
               return new FreezeIncOp(account, instructionSet, accountDetailRepository, freezeDetailRepository);
            case INC_DEC:
                return createIncDecOp0(instructionSet, account);
            default:
                throw new AccountException(ResponseCode.SYSTEM_ERROR, "创建记账操作错误");
        }
    }
    

    }

工厂方式模式(每个是一个类)

适用场景

1. 客户端不用关心创建过程

2. 需要创建的对象类型比较多,每一类对象的创建比较复杂

3. 对象的类型还存在较大的扩展可能性(增加一个对象时,也新增一种对应的对象方法)

public class Food {

}

public interface FoodFactory {
    Food makeFood(String name);
}

class ChineseFoodFactory implements FoodFactory {

    @Override
    public Food makeFood(String name) {
        if (name.equals("A")) {
            return new ChineseFoodA();
        } else if (name.equals("B")) {
            return new ChineseFoodB();
        } else {
            return null;
        }
    }
}

class AmericanFoodFactory implements FoodFactory {

    @Override
    public Food makeFood(String name) {
        if (name.equals("A")) {
            return new AmericanFoodA();
        } else if (name.equals("B")) {
            return new AmericanFoodB();
        } else {
            return null;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 先选择一个具体的工厂
        FoodFactory factory = new ChineseFoodFactory();
        // 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
        Food food = factory.makeFood("A");
    }
}
抽象工厂模式

三类工厂模式总结

  1. 简单工厂实现简单,内部封装多个对象的创建逻辑,所以容易造成工厂类过于庞大

  2. 工厂方法符合开闭原则,缺点是客户端要知道所需的工厂(该让调用方选择调哪个类)

  3. 如果要创建的对象是一个系列的、相互有关联关系,比如夜间模式的按钮、选框、文本,可以用抽象工厂(每个工厂都有车间、生产间等好几个职能,多对多的一个关系)

建造者模式

单例模式

原型模式

行为型模式

策略模式

适用场景

  1. 有多套同源的算法或逻辑

  2. 算法的数量增加和更迭速度快

  3. 多种算法和逻辑同时在线

    public class Main {

    public static interface PromotionPublishStrategy {
        void publishPromotion();
    }
    
    public static class CouponPublishStrategy implements PromotionPublishStrategy { // 具体策略A
    
        @Override
        public void publishPromotion() {
            System.out.println("发券");
        }
    }
    
    public static class PointPublishStrategy implements PromotionPublishStrategy { // 具体策略B
    
        @Override
        public void publishPromotion() {
            System.out.println("发积分");
        }
    }
    
    public static class StrategyFactory {
        public static PromotionPublishStrategy getStrategy(String strategyName) {
            if (strategyName.equals("point")) {
                return new PointPublishStrategy();
            } else if (strategyName.equals("coupon")) {
                return new CouponPublishStrategy();
            }
            throw new IllegalArgumentException("unknown strategy");
        }
    }
    
    public static class SimulativeABTest {
        public String hitFlowBucket(SimulativeUser user) {
            return user.getType();
        }
    }
    
    public static class SimulativeUser {
        protected final String type;
    
        public SimulativeUser(String type) {
            this.type = type;
        }
    
        public String getType() {
            return type;
        }
    }
    
    public static void main(String[] args) { // 策略选择
        SimulativeUser user = new SimulativeUser("point");
        SimulativeABTest abTest = new SimulativeABTest();
    
        PromotionPublishStrategy promotionPublishStrategy = StrategyFactory.getStrategy(abTest.hitFlowBucket(user));
        promotionPublishStrategy.publishPromotion();
    }
    

    }

访问者模式

目标:减少查询接口数量,提升查询效率

应用场景

  1. 一个服务拥有大量的数据内容(字段)

  2. 大量的服务需要查询这些数据内容

  3. 这些查询服务每次查询的数量内容差异很大(查询方不太一样,每个业务方有自己想要的字段)

    public class Main { public abstract class Element { // 底层订单信息查询器 protected final int id; protected List queryFields;

        protected Element(int id) {
            this.id = id;
        }
    
        public abstract Map<T, Object> query();
        public void setQueryFields(List<T> queryFields) {
            this.queryFields = queryFields;
        }
    
        public void accept(Visitor visitor) {
            visitor.visit(this);
            if (null == queryFields || queryFields.isEmpty()){
                System.out.println(this.getClass().getName() + "无查询需求,不执行任何操作");
                return;
            }
            System.out.println("查询字段列表:");
            queryFields.forEach(item ->
                    SyStem.out.print(item.getClass().getName() + ";"));
    
            System.out.println();
        }
    }
    public class Visitor extends <E extends Element,T> { // 变化的查询意图
        protected final List<Field> fields = new ArrayList<>();
        protected final T target; //备注:这种写法会导致类数量膨胀非常厉害,仅示意
    
        public Visitor(T target) {
            this.target = target;
        }
    
        public void addField(Field field) {
            fields.add(field);
        }
    
        public void visit(E element) {
            if (fields.isEmpty()) {
                return;
            }
            element.setQueryFields(fields);
            Map<Field, Object> resultMap = element.query();
            backFillResult(resultMap, target);
        }
    
        public void backFillResult(Map<Field, Object> resultMap, T target) {
            System.out.println("将字段回填到结果集中");
        }
    }
    
    public static class PurchaseInfo extends Element<PurchaseInfo.Field> { // 购买信息
        public PurchaseInfo(int id) { super(id); }
    
        protected enum Field implements demo.visitor.Field {
            PRICE, PRODUCT, AMOUNT, USER, STATUS, TIME
        }
    
        @Override
        public Map<Field, Object> query() {
            System.out.println("从数据库查询购买信息");
            return null;
        }
    }
    
    public static class RefundInfo extends Element<RefundInfo.Field> { // 退款信息
        public RefundInfo(int id) { super(id); }
    
        protected enum Field implements demo.visitor.Field {
            COMMISION, STATUS, TIME, USER, FEE
        }
    
        @Override
        public Map<RefundInfo.Field, Object> query() {
            System.out.println("从数据库查询退款信息");
            return null;
        }
    }
    
    public static class ContractInfo extends Element<ContractInfo.Field> { // 履约购买信息
        public ContractInfo(int id) { super(id); }
    
        protected enum Field implements demo.visitor.Field {
            DATE, AMOUNT, STATUS, CUSTOMER
        }
    
        @Override
        public Map<ContractInfo.Field, Object> query() {
            System.out.println("从数据库履约购买信息");
            return null;
        }
    }
    
    public static class PayInfo extends Element<PayInfo.Field> { // 履约支付信息
        public PayInfo(int id) { super(id); }
    
        protected enum Field implements demo.visitor.Field {
            AMOUNT, TYPE, OFFER, VALUE
        }
    
        @Override
        public Map<PayInfo.Field, Object> query() {
            System.out.println("从数据库履约支付信息");
            return null;
        }
    }
    
    public class Order { // 四类 具体的订单信息
        protected int fakeOrderId=1;
        protected int fakePurchaseId=2;
        protected int fakeRefundId=3;
        protected int fakeContractId=4;
        protected int fakePayId=5;
        protected Element<PurchaseInfo.Field> purchaseElement;
        protected Element<RefundInfo.Field> refundElement;
        protected Element<ContractInfo.Field> contractElement;
        protected Element<PayInfo.Field> payElement;
    
        public static class OrderRepository {
            public static Order query(int id) {
                Order order = new Order();
                order.purchaseElement = new PurchaseInfo(order.fakePurchaseId);
                order.refundElement = new RefundInfo(order.fakeRefundId);
                order.contractElement = new ContractInfo(order.fakeContractId);
                order.payElement = new PayInfo(order.fakePayId);
                return order;
            }
        }
    }
    
    public class Client { // 客户端使用接口
        public void query(int id, List<Field> queryFields, Object target) { // 接受若干查询元素,四类查询意图列表
            Order order = Order.OrderRepository.query(id);
            Visitor purchaseInfoVisitor = new Visitor<Order.PurchaseInfo, Object>(target);
            Visitor refundInfoVisitor = new Visitor<Order.RefundInfo, Object>(target);
            Visitor contractInfoVisitor = new Visitor<Order.ContractInfo, Object>(target);
            Visitor payInfoVisitor = new Visitor<Order.PayInfo, Object>(target);
            for (Field field : queryFields) {
                if (field instanceof Order.PurchaseInfo.Field) {
                    purchaseInfoVisitor.addField(field);
                } else if (field instanceof Order.RefundInfo.Field) {
                    refundInfoVisitor.addField(field);
                } else if (field instanceof Order.ContractInfo.Field) {
                    contractInfoVisitor.addField(field);
                } else if (field instanceof Order.PayInfo.Field) {
                    payInfoVisitor.addField(field);
                }
            }
            order.payElement.accept(payInfoVisitor);
            order.contractElement.accept(contractInfoVisitor);
            order.refundElement.accept(refundInfoVisitor);
            order.purchaseElement.accept(purchaseInfoVisitor);
        }
    }
    public static void main(String[] args) {
        List<Field> queryFields = new ArrayList<>();
        queryFields.add(Order.PurchaseInfo.Field.PRICE);
        queryFields.add(Order.PurchaseInfo.Field.AMOUNT);
        queryFields.add(Order.RefundInfo.Field.COMMISION);
        queryFields.add(Order.PayInfo.Field.VALUE);
        final int orderId = 1;
        CLient client = new Client();
        client.query(orderId, queryFields, new Object());
    }
    

    }

观察者模式

应用场景

  1. 某一个具体的执行步骤之后,有多少后续的下游步骤是不确定的,或者后续步骤数量过多

  2. 这些后续步骤的执行时间、时长以及结果,不改变已经执行的被观察步骤的执行结果和语义

  3. 这些后续步骤之间,没有结果相关性 (步骤的非相关性,没有执行依赖顺序的DAG,2、3两点都能说明,解耦)

  4. 注意:如果有执行顺序DAG,依赖状态等,就不该用观察者模式了

    public class Main {

    public interface OrderStatusChangeObserver {
        void onStatusChange(OrderStatus orderStatus);
    }
    
    public interface StatusChangePublisher {
        void register(OrderStatusChangeObserver orderStatusChangeObserver);
        void unregister(OrderStatusChangeObserver orderStatusChangeObserver);
        void notifyObservers();
    }
    
    public enum OrderStatus implements StatusChangePublisher {
        CREATE_SUCCESS, REFUND_SUCCESS; // 两个被观察者,创建成功,退款成功
        private List<OrderStatusChangeObserver> observers = new ArrayList<>();
        @Override
        public void register(OrderStatusChangeObserver orderStatusChangeObserver) { // 注册
            observers.add(orderStatusChangeObserver);
        }
    
        @Override
        public void unregister(OrderStatusChangeObserver orderStatusChangeObserver) { // 取消注册
            observers.remove(orderStatusChangeObserver);
        }
    
        @Override
        public void notifyObservers() { // 通知所有被观察者
            observers.forEach(orderStatusChangeObserver -> orderStatusChangeObserver.onStatusChange(this));
        }
    }
    
    public static class OrderStatusChangeObserverForCreateIndex implements OrderStatusChangeObserver  {
    
        @Override
        public void onStatusChange(OrderStatus orderStatus) {
            System.out.println("订单索引更新成功");
        }
    }
    
    public static class OrderStatusChangeObserverForSentMessage implements OrderStatusChangeObserver  {
    
        @Override
        public void onStatusChange(OrderStatus orderStatus) {
            System.out.println("退款短信发送成功");
        }
    }
    
    public static class CreateProcessWorkflow {
    
        public void createOrder(Object parameters) {
            System.out.println("创建订单");
            OrderStatus.CREATE_SUCCESS.notifyObservers();
        }
    }
    
    public static class RefundProcessWorkflow  {
    
        public void refund(Object parameters) {
            System.out.println("退款成功");
            OrderStatus.REFUND_SUCCESS.notifyObservers();
        }
    }
    
    public static void main(String[] args) { // 注册观察者
        OrderStatusChangeObserver createSuccessObserver = new OrderStatusChangeObserverForCreateIndex();
        OrderStatusChangeObserver refundSuccessObserver = new OrderStatusChangeObserverForSentMessage();
        CreateProcessWorkflow orderCreateWorkflow = new CreateProcessWorkflow();
        RefundProcessWorkflow orderRefundWorkflow = new RefundProcessWorkflow();
        OrderStatus.CREATE_SUCCESS.register(createSuccessObserver);
        OrderStatus.REFUND_SUCCESS.register(refundSuccessObserver);
        OrderStatus.REFUND_SUCCESS.register(createSuccessObserver);
        orderCreateWorkflow.createOrder(new Object());
        orderRefundWorkflow.refund(new Object());
    }
    

    }

中介模式(调停者模式)

常用场景
  1. 消息队列的Broker

  2. MVC模式中的Controller

  3. PC中的主板总线(PCIE总线)

通过中介者进行交互,外部模块职责更加单一

应用场景
  1. 一个过程中有很多参与方,在不同场景下,某个参与者的结果可能对流程呈现出不同的影响

  2. 参与者之间无法也没有必要完全感知和处理不同场景的上游结果和下游步骤(没有必要和所有参与者交互,发送消息给到中介者沟通和通信)

  3. 如果多个模块之间需要通信,需要思考模块本身设计是否合理

  4. 中介模式运用的前提:模块的业务能力建模和边界划分清晰

责任链模式

备忘录模式

命令模式

解释器模式

模板模式

UML类图

blog.csdn.net/qq_45087487…