Java设计模式简单入门
1. 设计模式概述
1.1 什么是设计模式?
设计模式(Design Pattern)是面向对象编程中解决常见问题的经典解决方案。它们是前人经验的总结,代表了最佳实践。设计模式并不是具体的代码,而是描述在各种不同情况下如何解决问题的方案。
设计模式有以下特点:
- 是解决特定问题的经验总结
- 是被广泛验证过的解决方案
- 是可以被反复使用的模板
- 提高代码的可重用性、可读性和可靠性
1.2 设计模式的历史
设计模式的概念最初由建筑师克里斯托弗·亚历山大提出,后来被Gang of Four(GoF)引入软件开发领域。1994年,Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著的《设计模式:可复用面向对象软件的基础》一书,正式确立了23种经典设计模式。
1.3 设计模式的重要性
- 提高代码质量:使代码更清晰、更易于理解
- 增强可维护性:更容易修改和扩展
- 促进团队协作:提供通用术语和模板
- 减少开发时间:使用成熟方案快速解决问题
- 降低风险:采用经过验证的解决方案
2. 面向对象设计原则
在学习设计模式之前,需要了解一些基本的设计原则:
2.1 SOLID原则
- 单一职责原则(SRP):一个类应该只有一个引起它变化的原因
- 开闭原则(OCP):对扩展开放,对修改关闭
- 里氏替换原则(LSP):子类必须能够替换其基类
- 接口隔离原则(ISP):客户端不应该依赖它们不需要的接口
- 依赖倒置原则(DIP):高层模块不应该依赖低层模块,两者都应该依赖抽象
2.2 其他重要原则
- 迪米特法则(最少知识原则):一个对象应该对其他对象保持最少的了解
- 合成复用原则:优先使用组合而非继承
3. 设计模式分类
根据GoF的分类,设计模式分为三大类:
3.1 创建型模式(Creational Patterns)
- 单例模式(Singleton Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
3.2 结构型模式(Structural Patterns)
- 适配器模式(Adapter Pattern)
- 装饰器模式(Decorator Pattern)
- 代理模式(Proxy Pattern)
- 外观模式(Facade Pattern)
- 桥接模式(Bridge Pattern)
- 组合模式(Composite Pattern)
- 享元模式(Flyweight Pattern)
3.3 行为型模式(Behavioral Patterns)
- 策略模式(Strategy Pattern)
- 模板方法模式(Template Method Pattern)
- 观察者模式(Observer Pattern)
- 迭代器模式(Iterator Pattern)
- 责任链模式(Chain of Responsibility Pattern)
- 命令模式(Command Pattern)
- 备忘录模式(Memento Pattern)
- 状态模式(State Pattern)
- 访问者模式(Visitor Pattern)
- 中介者模式(Mediator Pattern)
- 解释器模式(Interpreter Pattern)
4. 创建型模式详解
4.1 单例模式(Singleton Pattern)
4.1.1 模式意图
确保一个类只有一个实例,并提供一个全局访问点。
4.1.2 应用场景
- 配置文件管理器
- 日志记录器
- 数据库连接池
- 线程池
4.1.3 实现方式
饿汉式(线程安全):
java
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
懒汉式(线程不安全):
java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
双重检查锁定(线程安全):
java
public class DoubleCheckLockingSingleton {
private static volatile DoubleCheckLockingSingleton instance;
private DoubleCheckLockingSingleton() {}
public static DoubleCheckLockingSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckLockingSingleton.class) {
if (instance == null) {
instance = new DoubleCheckLockingSingleton();
}
}
}
return instance;
}
}
静态内部类(推荐):
java
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
private static class SingletonHolder {
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举(最安全):
java
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
System.out.println("Do something");
}
}
4.1.4 优缺点
优点:
- 内存中只有一个实例,节约内存
- 全局访问点,便于控制
缺点:
- 扩展困难
- 违反单一职责原则
- 测试困难
4.2 工厂方法模式(Factory Method Pattern)
4.2.1 模式意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。
4.2.2 应用场景
- 日志记录器选择
- 数据库连接器
- UI控件创建
4.2.3 实现
java
// 产品接口
interface Product {
void use();
}
// 具体产品
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using product A");
}
}
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using product B");
}
}
// 工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂
class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.use(); // 输出: Using product A
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.use(); // 输出: Using product B
}
}
4.2.4 优缺点
优点:
- 符合开闭原则
- 解耦合
- 支持依赖注入
缺点:
- 类数量增加
- 复杂度提高
4.3 抽象工厂模式(Abstract Factory Pattern)
4.3.1 模式意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
4.3.2 应用场景
- 跨平台UI界面
- 数据库访问层
- 游戏开发中的主题包
4.3.3 实现
java
// 抽象产品A
interface Button {
void paint();
}
// 抽象产品B
interface Checkbox {
void paint();
}
// Windows风格的具体产品
class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("Windows button painted");
}
}
class WindowsCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("Windows checkbox painted");
}
}
// MacOS风格的具体产品
class MacButton implements Button {
@Override
public void paint() {
System.out.println("Mac button painted");
}
}
class MacCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("Mac checkbox painted");
}
}
// 抽象工厂
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具体工厂
class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
// 客户端
public class Application {
private Button button;
private Checkbox checkbox;
public Application(GUIFactory factory) {
this.button = factory.createButton();
this.checkbox = factory.createCheckbox();
}
public void paint() {
button.paint();
checkbox.paint();
}
public static void main(String[] args) {
String osName = System.getProperty("os.name").toLowerCase();
GUIFactory factory;
if (osName.contains("win")) {
factory = new WindowsFactory();
} else {
factory = new MacFactory();
}
Application app = new Application(factory);
app.paint();
}
}
4.4 建造者模式(Builder Pattern)
4.4.1 模式意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
4.4.2 应用场景
- SQL查询构造器
- HTTP请求构造器
- 复杂对象的创建
4.4.3 实现
java
// 产品类
class Meal {
private String food;
private String drink;
private String dessert;
private Meal(Builder builder) {
this.food = builder.food;
this.drink = builder.drink;
this.dessert = builder.dessert;
}
public static class Builder {
private String food;
private String drink;
private String dessert;
public Builder setFood(String food) {
this.food = food;
return this;
}
public Builder setDrink(String drink) {
this.drink = drink;
return this;
}
public Builder setDessert(String dessert) {
this.dessert = dessert;
return this;
}
public Meal build() {
return new Meal(this);
}
}
@Override
public String toString() {
return "Meal{" +
"food='" + food + '\'' +
", drink='" + drink + '\'' +
", dessert='" + dessert + '\'' +
'}';
}
}
// 客户端
public class BuilderDemo {
public static void main(String[] args) {
Meal meal = new Meal.Builder()
.setFood("Burger")
.setDrink("Coke")
.setDessert("Ice Cream")
.build();
System.out.println(meal);
}
}
4.5 原型模式(Prototype Pattern)
4.5.1 模式意图
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
4.5.2 应用场景
- 对象克隆
- 深拷贝和浅拷贝操作
4.5.3 实现
java
interface Prototype {
Prototype clone();
}
class ConcretePrototype implements Prototype, Cloneable {
private String name;
private int age;
public ConcretePrototype(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// Getter和Setter方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "ConcretePrototype{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
5. 结构型模式详解
5.1 适配器模式(Adapter Pattern)
5.1.1 模式意图
将一个类的接口转换成客户希望的另一个接口。
5.1.2 应用场景
- 第三方库集成
- 旧系统接口兼容
- 不同数据格式转换
5.1.3 实现
java
// 目标接口
interface MediaPlayer {
void play(String audioType, String fileName);
}
// 被适配的类
class AdvancedMediaPlayer {
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: " + fileName);
}
}
// 适配器
class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer.playMp4(fileName);
}
}
}
class VlcPlayer extends AdvancedMediaPlayer {
// 实现播放VLC的方法
}
class Mp4Player extends AdvancedMediaPlayer {
// 实现播放MP4的方法
}
// 客户端
class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
} else if (audioType.equalsIgnoreCase("vlc") ||
audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("Invalid media. " +
audioType + " format not supported");
}
}
}
5.2 装饰器模式(Decorator Pattern)
5.2.1 模式意图
动态地给一个对象添加一些额外的职责。
5.2.2 应用场景
- Java IO流
- Servlet过滤器
- 缓存装饰
5.2.3 实现
java
// 抽象组件
interface Coffee {
String getDescription();
double getCost();
}
// 具体组件
class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple coffee";
}
@Override
public double getCost() {
return 1.0;
}
}
// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription();
}
@Override
public double getCost() {
return decoratedCoffee.getCost();
}
}
// 具体装饰器
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", milk";
}
@Override
public double getCost() {
return super.getCost() + 0.5;
}
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", sugar";
}
@Override
public double getCost() {
return super.getCost() + 0.2;
}
}
// 客户端测试
public class DecoratorDemo {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription() + ": $" + coffee.getCost());
Coffee milkCoffee = new MilkDecorator(new SimpleCoffee());
System.out.println(milkCoffee.getDescription() + ": $" + milkCoffee.getCost());
Coffee sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
System.out.println(sugarMilkCoffee.getDescription() + ": $" + sugarMilkCoffee.getCost());
}
}
5.3 代理模式(Proxy Pattern)
5.3.1 模式意图
为其他对象提供一种代理以控制对这个对象的访问。
5.3.2 应用场景
- 远程代理
- 虚拟代理
- 保护代理
- 智能引用
5.3.3 实现
java
// 主题接口
interface Image {
void display();
}
// 真实主题
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading " + fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
}
// 代理
class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
// 客户端
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
5.4 外观模式(Facade Pattern)
5.4.1 模式意图
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
5.4.2 应用场景
- 简化复杂系统的接口
- 分层系统架构
- 框架设计
5.4.3 实现
java
// 子系统类
class CPU {
public void freeze() { System.out.println("CPU: freeze"); }
public void jump(long position) { System.out.println("CPU: jump to " + position); }
public void execute() { System.out.println("CPU: execute"); }
}
class Memory {
public void load(long position, byte[] data) {
System.out.println("Memory: load data at " + position);
}
}
class HardDrive {
public byte[] read(long lba, int size) {
System.out.println("HardDrive: read " + size + " bytes from LBA " + lba);
return new byte[size];
}
}
// 外观类
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
public void start() {
cpu.freeze();
memory.load(0, hardDrive.read(0, 1024));
cpu.jump(0);
cpu.execute();
}
}
// 客户端
public class FacadeDemo {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.start();
}
}
6. 行为型模式详解
6.1 策略模式(Strategy Pattern)
6.1.1 模式意图
定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。
6.1.2 应用场景
- 排序算法选择
- 支付方式选择
- 计算策略
6.1.3 实现
java
// 策略接口
interface Strategy {
int doOperation(int num1, int num2);
}
// 具体策略
class OperationAdd implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
class OperationSubtract implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
class OperationMultiply implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
// 上下文
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
// 客户端
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
6.2 观察者模式(Observer Pattern)
6.2.1 模式意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
6.2.2 应用场景
- 事件驱动系统
- MVC架构中的模型-视图关系
- 发布-订阅系统
6.2.3 实现
import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
void update(String message);
}
// 主题接口
interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers(String message);
}
// 具体主题
class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setNews(String news) {
this.news = news;
notifyObservers(news);
}
}
// 具体观察者
class NewsChannel implements Observer {
private String news;
@Override
public void update(String message) {
this.news = message;
System.out.println("NewsChannel received news: " + news);
}
}
// 客户端
public class ObserverPatternDemo {
public static void main(String[] args) {
NewsAgency newsAgency = new NewsAgency();
NewsChannel channel1 = new NewsChannel();
NewsChannel channel2 = new NewsChannel();
newsAgency.attach(channel1);
newsAgency.attach(channel2);
newsAgency.setNews("Breaking News: Java 17 Released!");
}
}
6.3 模板方法模式(Template Method Pattern)
6.3.1 模式意图
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
6.3.2 应用场景
- 框架设计
- 算法框架
- 业务流程
6.3.3 实现
java
abstract class Game {
// 模板方法
public final void play() {
initialize();
startPlay();
endPlay();
}
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
}
class Cricket extends Game {
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
}
class Football extends Game {
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
}
// 客户端
public class TemplateMethodPatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
6.4 命令模式(Command Pattern)
6.4.1 模式意图
将一个请求封装为一个对象,从而使您可以用不同的请求对客户进行参数化。
6.4.2 应用场景
- 撤销/重做功能
- 事务处理
- 队列请求
6.4.3 实现
java
// 命令接口
interface Command {
void execute();
}
// 接收者
class Light {
public void turnOn() {
System.out.println("Light is turned on");
}
public void turnOff() {
System.out.println("Light is turned off");
}
}
// 具体命令
class TurnOnLightCommand implements Command {
private Light light;
public TurnOnLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
class TurnOffLightCommand implements Command {
private Light light;
public TurnOffLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
// 调用者
class Switch {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
// 客户端
public class CommandPatternDemo {
public static void main(String[] args) {
Light livingRoomLight = new Light();
Command lightOn = new TurnOnLightCommand(livingRoomLight);
Command lightOff = new TurnOffLightCommand(livingRoomLight);
Switch lightSwitch = new Switch();
lightSwitch.setCommand(lightOn);
lightSwitch.executeCommand();
lightSwitch.setCommand(lightOff);
lightSwitch.executeCommand();
}
}
7. 设计模式进阶应用
7.1 模式组合使用
在实际开发中,经常需要组合多个设计模式来解决复杂问题。例如:
- MVC架构中结合了观察者模式、策略模式、组合模式等
- Spring框架中大量使用了工厂模式、代理模式、模板方法模式等
- MyBatis框架中使用了建造者模式、工厂模式、代理模式等
7.2 反模式识别
虽然设计模式有很多优点,但也要注意避免滥用:
- 过度设计:为了使用模式而使用模式
- 模式误用:在不合适的地方使用某种模式
- 复杂性增加:引入不必要的抽象层次
7.3 性能考虑
某些设计模式可能会带来性能开销:
- 代理模式可能增加调用开销
- 装饰器模式可能导致对象嵌套过深
- 观察者模式可能导致内存泄漏
8. 实战案例分析
8.1 日志系统设计
使用单例模式、策略模式、装饰器模式构建日志系统:
java
// 日志接口
interface Logger {
void log(String message);
}
// 文件日志实现
class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Logging to file: " + message);
}
}
// 控制台日志实现
class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Logging to console: " + message);
}
}
// 日志策略
class LoggerFactory {
public static Logger getLogger(String type) {
if ("file".equalsIgnoreCase(type)) {
return new FileLogger();
} else if ("console".equalsIgnoreCase(type)) {
return new ConsoleLogger();
}
return new ConsoleLogger();
}
}
// 日志装饰器
class TimestampLogger implements Logger {
private Logger logger;
public TimestampLogger(Logger logger) {
this.logger = logger;
}
@Override
public void log(String message) {
logger.log("[" + System.currentTimeMillis() + "] " + message);
}
}
// 单例日志管理器
class LogManager {
private static volatile LogManager instance;
private Logger logger;
private LogManager() {
// 默认使用带时间戳的控制台日志
this.logger = new TimestampLogger(new ConsoleLogger());
}
public static LogManager getInstance() {
if (instance == null) {
synchronized (LogManager.class) {
if (instance == null) {
instance = new LogManager();
}
}
}
return instance;
}
public void log(String message) {
logger.log(message);
}
public void setLogger(Logger logger) {
this.logger = new TimestampLogger(logger);
}
}
8.2 缓存系统设计
使用单例模式、策略模式、观察者模式构建缓存系统:
java
import java.util.HashMap;
import java.util.Map;
// 缓存接口
interface Cache<K, V> {
V get(K key);
void put(K key, V value);
void remove(K key);
void clear();
}
// LRU缓存实现
class LRUCache<K, V> implements Cache<K, V> {
private Map<K, V> cache;
private int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
this.cache = new HashMap<>();
}
@Override
public V get(K key) {
return cache.get(key);
}
@Override
public void put(K key, V value) {
if (cache.size() >= capacity) {
// 简化的LRU实现,实际应使用LinkedHashMap
K firstKey = cache.keySet().iterator().next();
cache.remove(firstKey);
}
cache.put(key, value);
}
@Override
public void remove(K key) {
cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
}
// 缓存工厂
class CacheFactory {
public static <K, V> Cache<K, V> createCache(String type, int capacity) {
if ("lru".equalsIgnoreCase(type)) {
return new LRUCache<>(capacity);
}
return new LRUCache<>(capacity);
}
}
// 缓存管理器
class CacheManager<K, V> {
private static volatile CacheManager instance;
private Cache<K, V> cache;
private CacheManager() {
this.cache = CacheFactory.createCache("lru", 100);
}
public static <K, V> CacheManager<K, V> getInstance() {
if (instance == null) {
synchronized (CacheManager.class) {
if (instance == null) {
instance = new CacheManager<>();
}
}
}
return instance;
}
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
cache.put(key, value);
}
public void remove(K key) {
cache.remove(key);
}
}
9. 学习路径建议
9.1 入门阶段
- 理解面向对象基本原则
- 掌握常用设计模式的基本概念
- 熟悉每种模式的典型应用场景
- 阅读经典设计模式书籍
9.2 进阶阶段
- 深入理解设计模式的本质
- 学习模式间的关联和区别
- 阅读开源项目的源码
- 在项目中尝试应用设计模式
9.3 精通阶段
- 能够灵活组合多种设计模式
- 能够识别和避免反模式
- 能够根据具体场景选择合适的模式
- 能够设计出符合设计原则的架构
10. 总结
设计模式是软件开发中宝贵的经验总结,掌握它们有助于:
- 提高代码质量
- 增强代码可维护性
- 促进团队协作
- 加速问题解决
但要注意,设计模式不是银弹,应在合适的地方使用合适的模式。随着经验的积累,你会更好地理解和应用这些模式。
记住:设计模式的目的是解决问题,而不是为了使用模式而使用模式。始终以解决实际问题为导向,选择最适合的方案。
11. 代码整洁实践指南
在应用设计模式的同时,还需要遵循代码整洁的最佳实践。整洁的代码不仅易于理解和维护,还能减少错误的发生。以下是几个重要的代码整洁实践:
11.1 方法长度控制
方法体不要太长,最好不要超过80行 。过长的方法难以理解,增加了维护难度。如果一个方法超过80行,应该考虑将其拆分为多个更小的方法。在IDEA中,可以使用快捷键 Ctrl+Alt+M 来快速提取方法。
java
// 不好的例子:方法过长
public void processUserData() {
// 100行代码...
}
// 好的例子:将功能拆分到多个方法中
public void processUserData() {
validateInput();
transformData();
saveToDatabase();
sendNotification();
}
private void validateInput() {
// 输入验证逻辑
}
private void transformData() {
// 数据转换逻辑
}
private void saveToDatabase() {
// 数据库保存逻辑
}
private void sendNotification() {
// 通知发送逻辑
}
11.2 使用提前返回避免深层嵌套
使用if-return代替嵌套if语句。深层嵌套的if语句会降低代码的可读性,应该优先使用提前返回(guard clauses)来减少嵌套层级。
java
// 不好的例子:深层嵌套
public void processUser(User user) {
if (user != null) {
if (user.isActive()) {
if (user.hasPermission()) {
// 主要逻辑
System.out.println("Processing user: " + user.getName());
} else {
System.out.println("User doesn't have permission");
}
} else {
System.out.println("User is not active");
}
} else {
System.out.println("User is null");
}
}
// 好的例子:使用提前返回
public void processUser(User user) {
if (user == null) {
System.out.println("User is null");
return;
}
if (!user.isActive()) {
System.out.println("User is not active");
return;
}
if (!user.hasPermission()) {
System.out.println("User doesn't have permission");
return;
}
// 主要逻辑 - 代码更清晰
System.out.println("Processing user: " + user.getName());
}
11.3 复杂条件抽象
如果if条件过于复杂,应该抽象为方法或变量。复杂的条件判断会影响代码的可读性,应该将其提取为有意义的变量或方法。
``java
// 不好的例子:复杂条件判断
if (user.getAge() >= 18 && user.hasValidId() && user.getAccountBalance() > 1000 && !user.isBlacklisted()) {
// 处理逻辑
}
// 好的例子:将复杂条件抽象为变量
boolean isEligibleForService = user.getAge() >= 18 &&
user.hasValidId() &&
user.getAccountBalance() > 1000 &&
!user.isBlacklisted();
if (isEligibleForService) {
// 处理逻辑
}
// 或者抽象为方法
private boolean isEligibleForService(User user) {
return user.getAge() >= 18 &&
user.hasValidId() &&
user.getAccountBalance() > 1000 &&
!user.isBlacklisted();
}
### 11.4 空指针检查
**多使用空指针判断**。空指针异常是程序中最常见的运行时错误之一,应该在适当的位置进行空指针检查:
// 需要进行空指针检查的场景:
// 1. 方法入口参数检查
public void processUser(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
// 处理逻辑
}
// 2. 接收方法返回值时检查
UserService userService = getUserService();
if (userService != null) {
User user = userService.getCurrentUser();
if (user != null) {
// 使用user
}
}
// 3. 对象级联调用时检查
// 不安全的调用
String department = user.getProfile().getDepartment().getName();
// 安全的调用
if (user != null && user.getProfile() != null &&
user.getProfile().getDepartment() != null) {
String department = user.getProfile().getDepartment().getName();
}
// 或者使用Optional(Java 8+)
Optional.ofNullable(user)
.map(User::getProfile)
.map(Profile::getDepartment)
.map(Department::getName)
.orElse("Unknown");
### 11.5 字符串比较
**判断字符串是否相等时,使用equals方法**。使用 == 比较字符串可能会因为字符串常量池的问题导致错误的结果。
```java
// 错误的做法
if (status == "ACTIVE") {
// 逻辑
}
// 正确的做法
if ("ACTIVE".equals(status)) {
// 逻辑 - 推荐这种方式,可以避免空指针异常
}
// 或者
if (status != null && status.equals("ACTIVE")) {
// 逻辑
}
// 使用equalsIgnoreCase忽略大小写比较
if ("ACTIVE".equalsIgnoreCase(status)) {
// 逻辑
}
11.6 策略模式替代大量if-else
如果有大量if-else出现,考虑使用策略模式。当出现多个条件分支时,策略模式可以提高代码的可扩展性和可维护性。
java
// 不好的例子:大量if-else
public class PaymentProcessor {
public void processPayment(String paymentType, double amount) {
if ("CREDIT_CARD".equals(paymentType)) {
// 信用卡支付逻辑
} else if ("DEBIT_CARD".equals(paymentType)) {
// 借记卡支付逻辑
} else if ("PAYPAL".equals(paymentType)) {
// PayPal支付逻辑
} else if ("BANK_TRANSFER".equals(paymentType)) {
// 银行转账逻辑
}
// 每次新增支付方式都要修改这个方法
}
}
// 好的例子:使用策略模式
interface PaymentStrategy {
void processPayment(double amount);
}
class CreditCardPayment implements PaymentStrategy {
@Override
public void processPayment(double amount) {
// 信用卡支付逻辑
System.out.println("Processing credit card payment: " + amount);
}
}
class DebitCardPayment implements PaymentStrategy {
@Override
public void processPayment(double amount) {
// 借记卡支付逻辑
System.out.println("Processing debit card payment: " + amount);
}
}
class PayPalPayment implements PaymentStrategy {
@Override
public void processPayment(double amount) {
// PayPal支付逻辑
System.out.println("Processing PayPal payment: " + amount);
}
}
class PaymentContext {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.processPayment(amount);
}
}
11.7 枚举类型使用
如果有大量类型判断,将类型定义为枚举,便于维护和扩展。
java
// 不好的例子:使用字符串常量
public class OrderProcessor {
public void processOrder(String orderType) {
if ("NORMAL".equals(orderType)) {
// 普通订单处理
} else if ("PREMIUM".equals(orderType)) {
// 高级订单处理
} else if ("VIP".equals(orderType)) {
// VIP订单处理
}
}
}
// 好的例子:使用枚举
public enum OrderType {
NORMAL("普通订单"),
PREMIUM("高级订单"),
VIP("VIP订单");
private final String description;
OrderType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public class OrderProcessor {
public void processOrder(OrderType orderType) {
switch (orderType) {
case NORMAL:
// 普通订单处理
break;
case PREMIUM:
// 高级订单处理
break;
case VIP:
// VIP订单处理
break;
}
}
}
11.8 业务逻辑与数据查询分离
尽量用业务代码组装结果,代替多表联合查询。虽然多表联合查询在某些情况下性能更好,但过度依赖复杂的SQL查询会使业务逻辑难以理解和维护。
java
// 不好的例子:复杂的多表联合查询
// SQL: SELECT u.name, p.title, c.name FROM users u JOIN posts p ON u.id = p.user_id JOIN categories c ON p.category_id = c.id
// 好的例子:在业务代码中组装数据
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PostRepository postRepository;
@Autowired
private CategoryRepository categoryRepository;
public List<UserPostDTO> getUserPosts(Long userId) {
User user = userRepository.findById(userId);
List<Post> posts = postRepository.findByUserId(userId);
return posts.stream()
.map(post -> {
Category category = categoryRepository.findById(post.getCategoryId());
return new UserPostDTO(user.getName(), post.getTitle(), category.getName());
})
.collect(Collectors.toList());
}
}
``
### 11.9 结合设计模式的整洁代码实践
将设计模式与代码整洁实践相结合,可以进一步提高代码质量:
1. **工厂模式 + 参数校验**:在创建对象时进行参数校验
2. **建造者模式 + 早期返回**:在建造过程中进行有效性检查
3. **策略模式 + 枚举**:使用枚举来管理不同的策略
4. **模板方法模式 + 提前返回**:在模板方法中使用守卫子句
通过遵循这些代码整洁实践,可以确保您的代码不仅使用了正确的设计模式,还具备良好的可读性、可维护性和健壮性。