本文介绍Java中的代理模式,及一些常见的模式应用。
一、Java设计模式
Java中最常见的设计模式主要有23种,如表所示:
表格:Java设计模式分类
类型 | 设计模式 |
---|---|
创建型模式 | 单例模式(Singleton Pattern) 工厂方法模式(Factory Method Pattern) 抽象工厂模式(Abstract Factory Pattern) 建造者模式(Builder Pattern) 原型模式(Prototype Pattern) |
结构型模式 | 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 组合模式(Composite Pattern) 装饰者模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) |
行为型模式 | 责任链模式(Chain of Responsibility Pattern) 命令模式(Command Pattern) 解释器模式(Interpreter Pattern) 迭代器模式(Iterator Pattern) 中介者模式(Mediator Pattern) 备忘录模式(Memento Pattern) 观察者模式(Observer Pattern) 状态模式(State Pattern) 策略模式(Strategy Pattern) 模板方法模式(Template Method Pattern) 访问者模式(Visitor Pattern) |
二、单例模式(美团面试真题)
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式通常用于需要全局唯一实例的场景,如配置管理、日志记录、数据库连接等。单例模式可分为饿汉式和懒汉式两种。
1. 饿汉式(线程安全) :在类加载时就创建实例,但是可能会造成资源浪费。
代码实现:
bash
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
2. 懒汉式 :在使用时才创建对象实例,因此面对多线程时会产生线程安全问题。
代码:
bash
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3. 线程安全的单例模式(使用双重锁)
bash
public class Singleton{
private static Singleton instance;
private Singleton(){}
//获取单例的方法
public static Singleton getInstance(){
//第一重校验
if(instance == null){
synchronized (Singleton.class){
//第二重校验
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
三、工厂方法模式 VS 抽象方法模式
1. 工厂方法模式
- 工厂方法模式为每种产品创建一个具体工厂类,然后在使用时根据需要使用相应的具体工厂创建对象
- 优点:符合开闭原则,可以增加新的产品类而无需修改现有代码
- 缺点:需要为每种产品创建一个具体工厂类,增加了系统的复杂度和代码量
- 示例
bash
// 产品接口
interface Product {
void use();
}
// 具体产品A
class ConcreteProductA implements Product {
public void use() {
System.out.println("Using Product A");
}
}
// 具体产品B
class ConcreteProductB implements Product {
public void use() {
System.out.println("Using Product B");
}
}
// 抽象工厂
abstract class Creator {
public abstract Product factoryMethod();
}
// 具体工厂A
class ConcreteCreatorA extends Creator {
public Product factoryMethod() {
return new ConcreteProductA();
}
}
// 具体工厂B
class ConcreteCreatorB extends Creator {
public Product factoryMethod() {
return new ConcreteProductB();
}
}
public class Client {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.factoryMethod();
productA.use(); // 输出: Using Product A
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.use(); // 输出: Using Product B
}
}
2. 抽象方法模式
- 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
- 优点
① 分离了具体类的生成,使得产品之间的依赖关系更加一致。
② 提供了一个一致的接口,可以创建多个产品对象,使产品族的更换变得容易 - 缺点:新增产品族时需要修改抽象工厂接口,违反了开闭原则,增加复杂性
- 示例
bash
// 抽象产品A
interface ProductA {
void use();
}
// 抽象产品B
interface ProductB {
void use();
}
// 具体产品A1
class ConcreteProductA1 implements ProductA {
public void use() {
System.out.println("Using Product A1");
}
}
// 具体产品B1
class ConcreteProductB1 implements ProductB {
public void use() {
System.out.println("Using Product B1");
}
}
// 具体产品A2
class ConcreteProductA2 implements ProductA {
public void use() {
System.out.println("Using Product A2");
}
}
// 具体产品B2
class ConcreteProductB2 implements ProductB {
public void use() {
System.out.println("Using Product B2");
}
}
// 抽象工厂
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA1();
}
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA2();
}
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.use(); // 输出: Using Product A1
productB1.use(); // 输出: Using Product B1
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.use(); // 输出: Using Product A2
productB2.use(); // 输出: Using Product B2
}
}
3. 二者区别(华为面试)
特性 | 工厂方法模式 (Factory Method) | 抽象工厂模式 (Abstract Factory) |
---|---|---|
定义 | 定义一个创建对象的接口,但由子类决定实例化哪个类。 | 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 |
使用场景 | 当一个类不知道它所需要的对象的具体类时。 | 当系统要独立于它的产品的创建、组合和表示时。 |
优点 | 1. 符合开闭原则。 2. 客户端不需要修改代码就可以使用新创建的对象。 | 1. 分离了具体类的生成。 2. 提供了一致的接口,便于创建多个相关产品对象。 |
缺点 | 1. 需要为每种产品创建一个具体工厂类。 2. 增加了系统的复杂度和代码量。 | 1. 新增产品族时需要修改抽象工厂接口,违反开闭原则。 2. 增加了系统的复杂度。 |
主要角色 | 1. 抽象产品 2. 具体产品 3. 抽象工厂 4. 具体工厂 | 1. 抽象产品 2. 具体产品 3. 抽象工厂 4. 具体工厂 |
产品创建的粒度 | 只创建单一产品对象。 | 创建一系列相关或依赖的产品对象。 |
四、策略模式
1. 定义
定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。
2. 示例
bash
interface Strategy {
void execute();
}
class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("Strategy A executed.");
}
}
class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("Strategy B executed.");
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
- 常见应用
五、观察者模式
1. 定义
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2. 示例(海康威视笔试:楼层着火通知)
bash
// 观察者接口
interface Observer {
void update(int floor); // 更新方法,传入楼层信息
}
// 具体的观察者类(保安类)
class SecurityGuard implements Observer {
private String name;
public SecurityGuard(String name) {
this.name = name;
}
@Override
public void update(int floor) {
System.out.println("Security Guard " + name + " received fire alert from floor " + floor);
if (floor == Integer.parseInt(name)) {
System.out.println("Security Guard " + name + " is handling the fire.");
} else {
System.out.println("Security Guard " + name + " is not responsible for this floor.");
}
}
}
// 被观察者接口
interface Subject{
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 移除观察者
void notifyObservers(int floor); // 通知观察者
}
// 具体主题类(楼层类)
class Floor implements Subject {
private List<Observer> observers; // 观察者列表
public Floor() {
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(int floor) {
for (Observer observer : observers) {
observer.update(floor);
}
}
// 模拟楼层着火
public void fireAlert(int floor) {
System.out.println("Fire alert on floor " + floor);
notifyObservers(floor);
}
}
六、外观模式
- 定义
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这一接口使得这一子系统更加容易使用 - 示例(海康笔试:以电脑启动为例)
bash
// CPU 类
class CPU {
public void start() {
System.out.println("CPU is starting...");
}
}
// Disk 类
class Disk {
public void start() {
System.out.println("Disk is starting...");
}
}
// Memory 类
class Memory {
public void start() {
System.out.println("Memory is starting...");
}
}
// 外观类
class ComputerFacade {
private CPU cpu;
private Disk disk;
private Memory memory;
public ComputerFacade() {
this.cpu = new CPU();
this.disk = new Disk();
this.memory = new Memory();
}
public void startComputer() {
System.out.println("Starting computer...");
disk.start();
cpu.start();
memory.start();
System.out.println("Computer started successfully.");
}
}
七、责任链模式
1. 定义
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
2. 示例
bash
在这里插入代码片abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(int request);
}
class ConcreteHandler1 extends Handler {
@Override
public void handleRequest(int request) {
if (request < 10) {
System.out.println("Handler1 handled request " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
class ConcreteHandler2 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 10) {
System.out.println("Handler2 handled request " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
八、Java IO中设计模式
- 装饰者模式
装饰者模式允许动态地将职责添加到对象中,通过将对象封装在装饰对象中来增强对象的功能。(InputStream 和 OutputStream 及其子类)
2. 适配器模式
适配器模式允许将一个类的接口转换为另一个接口,以便不同接口的类可以一起工作。(InputStreamReader 和 OutputStreamWriter 类)
3. 桥接模式
桥接模式用于将抽象部分与它的实现部分分离,使它们可以独立变化。(Reader 和 Writer 抽象类及其具体实现类)
4. 迭代器模式
迭代器模式用于提供一种方法来顺序访问集合中的每个元素,而不暴露其底层表示。(Scanner 类用于逐行读取输入)
5. 责任链模式
FilterInputStream 和 FilterOutputStream 类
6. 工厂方法模式
FileReader 和 FileWriter 类