设计模式学习

一、工厂模式概述

工厂模式属于创建型设计模式,主要用于对象的创建,将对象的创建与使用分离,提高代码的灵活性和可维护性。

为什么需要工厂模式?

  1. 解耦:将对象的创建与使用分离
  2. 降低代码重复:集中管理对象的创建逻辑
  3. 提高扩展性:新增产品类时不影响现有代码
  4. 统一管理:可以对创建过程进行统一控制

二、简单工厂模式(Simple Factory)

1. 定义

定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例通常具有共同的父类或接口。

2. 结构

  • ​工厂类(Factory)​​:负责创建具体产品
  • ​抽象产品(Product)​​:定义产品的接口
  • ​具体产品(ConcreteProduct)​​:实现抽象产品接口的具体类

// 抽象产品
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 简单工厂
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        return null;
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Product product = SimpleFactory.createProduct("A");
        product.use(); // 输出: 使用产品A
    }
}

4. 优缺点

​优点​​:

  • 客户端无需知道具体产品类名,只需知道对应参数
  • 实现了对象的创建和使用的分离

​缺点​​:

  • 工厂类集中了所有产品的创建逻辑,职责过重
  • 新增产品需要修改工厂类,违反开闭原则
  • 难以扩展复杂的产品结构

5. 面试常见问题

  • 简单工厂模式违反了哪些设计原则?(开闭原则)
  • 简单工厂模式和直接new一个对象有什么区别?(解耦、集中管理)
  • 简单工厂模式适用于什么场景?(创建对象较少且不频繁变化)

三、工厂方法模式(Factory Method)

1. 定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

2. 结构

  • ​抽象工厂(Factory)​​:声明工厂方法
  • ​具体工厂(ConcreteFactory)​​:实现工厂方法,返回具体产品
  • ​抽象产品(Product)​​:定义产品接口
  • ​具体产品(ConcreteProduct)​​:实现产品接口

// 抽象产品
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 抽象工厂
interface Factory {
    Product createProduct();
}

// 具体工厂A
class ConcreteFactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂B
class ConcreteFactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactoryA();
        Product product = factory.createProduct();
        product.use(); // 输出: 使用产品A
    }
}

4. 优缺点

​优点​​:

  • 用户只需关心所需产品对应的工厂,无需关心创建细节
  • 新增产品时只需添加对应的工厂类,符合开闭原则
  • 可以形成基于产品的等级结构

​缺点​​:

  • 类的个数容易过多,增加系统复杂度
  • 增加了系统的抽象性和理解难度

5. 面试常见问题

  • 工厂方法模式如何解决简单工厂模式的问题?(通过多态延迟实例化到子类)
  • 工厂方法模式和简单工厂模式的主要区别是什么?(是否使用继承和多态)
  • JDK中哪些地方使用了工厂方法模式?(如Collection.iterator(), URLStreamHandlerFactory)

四、抽象工厂模式(Abstract Factory)

1. 定义

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

2. 结构

  • ​抽象工厂(AbstractFactory)​​:声明创建一系列产品的方法
  • ​具体工厂(ConcreteFactory)​​:实现创建具体产品的方法
  • ​抽象产品(AbstractProduct)​​:为每种产品声明接口
  • ​具体产品(ConcreteProduct)​​:实现抽象产品接口的具体类
    // 抽象产品A
    interface AbstractProductA {
        void use();
    }
    
    // 具体产品A1
    class ProductA1 implements AbstractProductA {
        @Override
        public void use() {
            System.out.println("使用A1产品");
        }
    }
    
    // 具体产品A2
    class ProductA2 implements AbstractProductA {
        @Override
        public void use() {
            System.out.println("使用A2产品");
        }
    }
    
    // 抽象产品B
    interface AbstractProductB {
        void operate();
    }
    
    // 具体产品B1
    class ProductB1 implements AbstractProductB {
        @Override
        public void operate() {
            System.out.println("操作B1产品");
        }
    }
    
    // 具体产品B2
    class ProductB2 implements AbstractProductB {
        @Override
        public void operate() {
            System.out.println("操作B2产品");
        }
    }
    
    // 抽象工厂
    interface AbstractFactory {
        AbstractProductA createProductA();
        AbstractProductB createProductB();
    }
    
    // 具体工厂1
    class ConcreteFactory1 implements AbstractFactory {
        @Override
        public AbstractProductA createProductA() {
            return new ProductA1();
        }
    
        @Override
        public AbstractProductB createProductB() {
            return new ProductB1();
        }
    }
    
    // 具体工厂2
    class ConcreteFactory2 implements AbstractFactory {
        @Override
        public AbstractProductA createProductA() {
            return new ProductA2();
        }
    
        @Override
        public AbstractProductB createProductB() {
            return new ProductB2();
        }
    }
    
    // 客户端使用
    public class Client {
        public static void main(String[] args) {
            AbstractFactory factory = new ConcreteFactory1();
            AbstractProductA productA = factory.createProductA();
            AbstractProductB productB = factory.createProductB();
            productA.use();    // 输出: 使用A1产品
            productB.operate(); // 输出: 操作B1产品
        }
    }

4. 优缺点

​优点​​:

隔离了具体类的生成,客户端不需要知道具体类名 易于交换产品系列,只需改变具体工厂

​缺点​​:

  • 增加新的产品等级结构很复杂,需要修改抽象工厂和所有具体工厂
  • 增加了系统的抽象性和理解难度
  • 保证客户端始终只使用同一个产品族中的对象

5. 面试常见问题

  • 抽象工厂模式和工厂方法模式的主要区别是什么?(产品族 vs 单一产品)
  • 抽象工厂模式适用于什么场景?(需要创建一系列相关或依赖的对象)
  • Spring框架中哪里使用了抽象工厂模式?(如BeanFactory)

五、三种工厂模式对比

特性简单工厂模式工厂方法模式抽象工厂模式
复杂度
可扩展性差(修改工厂类)好(新增工厂类)好(新增工厂类)
适用场景创建对象较少单一产品等级结构多个产品等级结构
设计原则违反开闭原则符合开闭原则符合开闭原则
灵活性

六、实际应用场景

  • ​JDBC中的工厂模式​​:

    • DriverManager.getConnection() 是简单工厂
    • DataSource 是工厂方法
    • 不同数据库的驱动是抽象工厂的实现
  • ​Spring框架​​:

    • BeanFactory 是工厂方法模式
    • ApplicationContext 扩展了工厂方法模式
    • 不同环境的配置可以看作抽象工厂
  • ​日志框架​​:

    • LoggerFactory.getLogger() 是工厂方法
    • 不同日志实现(Log4j, JUL, SLF4J)是具体工厂

一、策略模式概述

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户端。

为什么需要策略模式?

​避免条件语句​​:消除大量的if-else或switch-case语句 ​​算法复用​​:相同算法可以在不同环境中使用 ​​扩展性好​​:新增策略不影响现有代码

二、策略模式结构

1. 核心角色

  • ​策略接口(Strategy)​​:定义所有支持的算法的公共接口
  • ​具体策略(ConcreteStrategy)​​:实现策略接口的具体算法类
  • ​上下文(Context)​​:持有一个策略对象的引用,通过策略接口与具体策略交互
    • ​符合开闭原则​​:对扩展开放,对修改关闭

三、策略模式优缺点

优点

​算法自由切换​​:策略类之间可以自由切换 ​​避免多重条件判断​​:消除了大量的条件语句 ​​扩展性良好​​:增加新策略很容易,符合开闭原则 ​​算法复用​​:相同算法可以在不同环境中使用

缺点

四、实际应用场景

  • ​客户端必须知道所有策略类​​:客户端需要了解不同策略的区别
  • ​策略类数量增加​​:每个策略都是一个类,可能增加系统复杂性
  • ​通信开销​​:如果策略需要访问上下文数据,可能需要复杂的接口设计
  • ​支付系统​​:多种支付方式的选择与切换
  • ​排序算法​​:根据不同场景选择快速排序、归并排序等
  • ​游戏AI​​:NPC根据情境选择不同行为策略
  • ​折扣系统​​:不同促销活动采用不同的折扣策略
  • ​路由算法​​:根据网络状况选择最优路由策略

1. 策略模式和工厂模式有什么区别?

​回答要点​​:

工厂模式是创建型模式,关注对象的创建;策略模式是行为型模式,关注行为的封装和切换 工厂模式解决"如何创建对象"的问题,策略模式解决"如何选择算法"的问题 工厂模式在创建后一般不改变对象,策略模式可以动态切换策略

2. 策略模式和状态模式有什么区别?

​回答要点​​:

3. 什么情况下应该使用策略模式?

​回答要点​​:

​回答要点​​:

  • 策略模式客户端需要知道所有策略,状态模式客户端不感知状态变化
  • 策略模式策略之间独立,状态模式状态之间可能相互转换
  • 策略模式关注算法选择,状态模式关注状态变化引起的行为变化
  • 当一个系统有许多类,它们的区别仅在于行为不同时
  • 需要动态地在几种算法中选择一种时
  • 需要避免使用多重条件判断语句时
  • 希望算法可以独立于使用它的客户端变化时
  • 对扩展开放:新增策略只需添加新策略类,无需修改现有代码
  • 对修改关闭:上下文类不需要因为新增策略而修改
  • 通过面向接口编程实现,依赖抽象而非具体实现

4. 策略模式如何符合开闭原则?

​回答要点​​:

  • 对扩展开放:新增策略只需添加新策略类,无需修改现有代码
  • 对修改关闭:上下文类不需要因为新增策略而修改
  • 通过面向接口编程实现,依赖抽象而非具体实现

5. 策略模式有哪些缺点?如何解决?

​回答要点​​:

6. 请举例说明你在项目中如何使用策略模式?

​回答示例​​:
"在我参与的电商项目中,我们使用策略模式实现了多种折扣计算方式。定义了一个DiscountStrategy接口,有会员折扣、满减折扣、促销折扣等实现。结账时根据活动类型自动选择对应策略计算最终价格。这样新增折扣类型时只需添加新策略类,不影响现有代码,也便于进行单元测试。"

  • 客户端必须了解所有策略:可以通过工厂模式或依赖注入隐藏创建细节
  • 策略类数量增加:合理设计策略层次结构,使用组合而非继承
  • 通信开销:设计良好的上下文接口,或使用共享数据对象

一、责任链模式概述

责任链模式(Chain of Responsibility)使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

为什么需要责任链模式?

  • ​解耦请求发送者和接收者​​:发送者无需知道具体由哪个对象处理
  • ​动态组合处理流程​​:可以灵活地增加或修改处理链
  • ​多对象处理请求​​:允许多个对象都有机会处理请求
  • ​符合单一职责原则​​:每个处理器只关注自己负责的部分

二、责任链模式优缺点

优点

​降低耦合度​​:请求发送者无需知道具体哪个对象会处理 ​​动态组合​​:可以运行时动态改变链中的成员或调整顺序 ​​灵活性高​​:新增处理者或改变处理顺序都很方便 ​​单一职责​​:每个处理者只关注自己负责的部分

缺点

三、实际应用场景

  • ​请求可能未被处理​​:没有保证请求一定会被处理
  • ​性能影响​​:长链可能导致请求处理延迟
  • ​调试困难​​:请求传递过程不易跟踪和调试
  • ​循环引用风险​​:不正确的链设置可能导致循环引用
  • ​审批流程​​:多级审批系统,如请假审批、费用报销
  • ​异常处理​​:Java异常处理机制(try-catch-finally)
  • ​过滤器/拦截器​​:Servlet Filter、Spring Interceptor
  • ​日志处理​​:不同级别的日志由不同处理器处理
  • ​游戏事件处理​​:游戏中的输入事件传递处理

七、面试常见问题及回答

1. 责任链模式和装饰器模式有什么区别?

​回答要点​​:

责任链模式是行为型模式,关注请求的传递和处理;装饰器模式是结构型模式,关注对象功能的动态添加 责任链模式处理者可以终止传递,装饰器模式通常会继续传递 责任链模式处理者通常不关心前驱后继的具体类型,装饰器模式装饰器知道被装饰对象

2. 如何避免责任链过长导致的性能问题?

​回答要点​​:

3. 责任链模式如何保证请求一定会被处理?

​回答要点​​:

4. 什么情况下不适合使用责任链模式?

​回答要点​​:

5. 责任链模式如何支持处理器的动态添加和移除?

​回答要点​​:

6. 请举例说明你在项目中如何使用责任链模式?

​回答示例​​:
"在我们项目的风控系统中,我们使用责任链模式实现了多层次的风险检查。每个风险检查点(如黑名单检查、信用评分检查、交易频率检查等)都是一个独立的处理器。当发起交易时,请求会依次通过这些检查点。每个检查点只关注自己负责的风险维度,通过则传递给下一个检查点,不通过则终止流程并返回风险提示。这种设计使我们能够灵活地添加新的风险检查点而不影响现有逻辑。"

  • 限制链的最大长度
  • 对频繁调用的处理器进行缓存
  • 使用异步处理机制
  • 定期评估和优化处理链结构
  • 对处理器进行性能监控和分析
  • 在链尾设置默认处理器处理所有未被处理的请求
  • 使用模板方法模式确保处理逻辑的一致性
  • 定义明确的处理结果返回机制
  • 请求必须有且只有一个处理器处理时
  • 处理顺序需要严格固定且不会变化时
  • 性能要求极高,无法接受链式调用的开销时
  • 处理逻辑过于简单,不需要多对象协作时
  • 维护处理器集合而非固定引用
  • 提供添加/移除处理器的方法
  • 使用组合模式管理复杂处理器结构
  • 可以结合工厂模式管理处理器实例
    • 可以引入"终结处理器"概念确保链的完整性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值