
1. 项目概述作为一名从业多年的软件工程师我深知设计模式在软件开发中的重要性。特别是在准备软考软件设计师考试时结构型与行为型设计模式往往是考生最头疼的部分。这篇文章将带你系统梳理这两大类设计模式的核心要点结合软考真题分析高频考点并提供可直接套用的代码模板。设计模式不是空中楼阁而是解决特定问题的经验总结。我在实际项目中发现很多开发者虽然能背诵23种设计模式的名称但在面对具体问题时却不知如何应用。更糟糕的是软考下午题常要求考生根据场景选择合适的设计模式并给出实现这需要真正的理解而非死记硬背。2. 结构型设计模式深度解析2.1 适配器模式(Adapter)适配器模式就像电源转换插头让不兼容的接口能够协同工作。在遗留系统改造中特别常见比如当我们需要将老系统的数据接口接入新平台时。// 老系统接口 class LegacySystem { public void oldRequest() { System.out.println(Legacy system processing); } } // 新系统期望的接口 interface NewSystem { void newRequest(); } // 适配器实现 class Adapter implements NewSystem { private LegacySystem legacy; public Adapter(LegacySystem legacy) { this.legacy legacy; } Override public void newRequest() { legacy.oldRequest(); } }注意适配器模式会增加系统复杂性仅在确实需要兼容旧接口时使用。过度使用会导致系统充满胶水代码。2.2 装饰器模式(Decorator)装饰器模式通过层层包装来动态添加功能比继承更灵活。Java IO流就是经典应用// 基础组件接口 interface Coffee { double getCost(); String getDescription(); } // 具体组件 class SimpleCoffee implements Coffee { public double getCost() { return 1.0; } public String getDescription() { return Simple coffee; } } // 装饰器基类 abstract class CoffeeDecorator implements Coffee { protected final Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee coffee; } public double getCost() { return decoratedCoffee.getCost(); } public String getDescription() { return decoratedCoffee.getDescription(); } } // 具体装饰器 class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); } public double getCost() { return super.getCost() 0.5; } public String getDescription() { return super.getDescription() , with milk; } }2.3 组合模式(Composite)组合模式让客户端可以统一处理单个对象和对象组合。文件系统是最佳示例class FileSystemComponent: def display(self, indent0): pass class File(FileSystemComponent): def __init__(self, name): self.name name def display(self, indent0): print( * indent f {self.name}) class Directory(FileSystemComponent): def __init__(self, name): self.name name self.children [] def add(self, component): self.children.append(component) def display(self, indent0): print( * indent f {self.name}) for child in self.children: child.display(indent 2)3. 行为型设计模式实战指南3.1 观察者模式(Observer)观察者模式实现对象间的一对多依赖让多个观察者对象同时监听某一主题对象。GUI事件处理、发布-订阅系统常用此模式。// 主题接口 interface ISubject { void RegisterObserver(IObserver observer); void RemoveObserver(IObserver observer); void NotifyObservers(); } // 具体主题 class WeatherStation : ISubject { private ListIObserver observers new ListIObserver(); private float temperature; public void RegisterObserver(IObserver observer) { observers.Add(observer); } public void RemoveObserver(IObserver observer) { observers.Remove(observer); } public void NotifyObservers() { foreach (var observer in observers) { observer.Update(temperature); } } public void SetTemperature(float temp) { temperature temp; NotifyObservers(); } } // 观察者接口 interface IObserver { void Update(float temperature); } // 具体观察者 class Display : IObserver { public void Update(float temperature) { Console.WriteLine($Current temperature: {temperature}°C); } }3.2 策略模式(Strategy)策略模式定义算法族分别封装起来使它们可以互相替换。支付方式选择是典型场景// 策略接口 class PaymentStrategy { pay(amount) { throw new Error(Method not implemented); } } // 具体策略 class CreditCardStrategy extends PaymentStrategy { constructor(cardNumber, cvv) { super(); this.cardNumber cardNumber; this.cvv cvv; } pay(amount) { console.log(Paid ${amount} using credit card ${this.cardNumber}); } } class PayPalStrategy extends PaymentStrategy { constructor(email, password) { super(); this.email email; this.password password; } pay(amount) { console.log(Paid ${amount} using PayPal account ${this.email}); } } // 上下文 class ShoppingCart { constructor(paymentStrategy) { this.paymentStrategy paymentStrategy; this.items []; } addItem(item) { this.items.push(item); } checkout() { const total this.items.reduce((sum, item) sum item.price, 0); this.paymentStrategy.pay(total); } }3.3 状态模式(State)状态模式允许对象在内部状态改变时改变其行为。电梯状态转换是经典案例// 状态接口 class ElevatorState { public: virtual void openDoors() 0; virtual void closeDoors() 0; virtual void move() 0; virtual void stop() 0; }; // 具体状态 class OpenState : public ElevatorState { public: void openDoors() override { cout Doors are already open endl; } void closeDoors() override { cout Closing doors endl; // 转换到ClosedState } void move() override { cout Cannot move while doors are open endl; } void stop() override { cout Already stopped with doors open endl; } }; // 上下文 class Elevator { private: ElevatorState* currentState; public: Elevator() : currentState(new OpenState()) {} void setState(ElevatorState* state) { delete currentState; currentState state; } void openDoors() { currentState-openDoors(); } void closeDoors() { currentState-closeDoors(); } void move() { currentState-move(); } void stop() { currentState-stop(); } };4. 软考高频考点与解题技巧4.1 设计模式识别题解题步骤分析题目场景找出系统需要解决的核心问题识别变化点确定哪些部分可能变化或需要扩展匹配模式特征创建型对象创建过程复杂结构型接口不匹配需要组合对象行为型对象间通信复杂算法需要切换实战技巧软考常考一个类需要根据不同情况创建不同对象→工厂方法需要统一处理整体与部分→组合模式需要动态添加功能→装饰器模式。4.2 设计模式实现题评分要点类图正确性40%类名、接口名准确关系继承、实现、组合、聚合正确代码完整性30%关键方法实现模式核心逻辑体现场景适用性20%模式选择合理解决题目描述的问题编码规范10%命名规范适当注释4.3 近三年高频考点统计设计模式出现频率常见考察形式工厂方法★★★★★创建不同格式文档适配器★★★★☆新旧系统接口兼容装饰器★★★★☆动态添加日志、加密等功能观察者★★★★☆事件通知系统策略★★★☆☆支付方式、排序算法切换组合★★★☆☆文件系统、菜单项处理5. 设计模式面试与实战常见问题5.1 面试高频问题解析Q1装饰器模式和继承有什么区别装饰器强调运行时动态添加功能继承是编译时静态决定。装饰器更灵活可以任意组合功能避免类爆炸问题。但装饰器会产生大量小对象可能影响性能。Q2观察者模式和发布-订阅模式的区别观察者模式中主题和观察者直接交互是松耦合的发布-订阅模式通过消息代理完全解耦发布者不知道订阅者的存在。系统复杂时发布-订阅更易扩展。Q3什么情况下不应该使用设计模式需求非常明确且不会变化性能是首要考虑因素项目非常小引入模式反而增加复杂度团队对模式不熟悉可能误用5.2 实际项目中的设计模式误用案例1过度设计某电商系统在初期就为所有业务接口添加适配器层实际上只有10%的接口需要适配。这增加了系统复杂度和维护成本。解决方案遵循YAGNI原则(You Arent Gonna Need It)只在确实需要时引入设计模式。案例2模式混用混乱一个订单处理系统同时使用了策略模式和状态模式导致状态转换和算法切换逻辑纠缠不清。解决方案明确每种模式的职责边界。状态模式关注对象内部状态改变引起的行为变化策略模式关注算法的可替换性。5.3 设计模式性能考量对象创建开销装饰器、组合模式会创建大量小对象享元模式可以优化对象创建方法调用开销代理模式增加间接调用虚方法调用比接口方法调用更快内存占用观察者模式中观察者列表可能很大可以用弱引用避免内存泄漏// 使用WeakHashMap实现观察者列表 public class Observable { private MapObserver, ? observers new WeakHashMap(); public void addObserver(Observer o) { observers.put(o, null); } public void notifyObservers() { for (Observer o : observers.keySet()) { o.update(this); } } }6. 设计模式学习路线与资源推荐6.1 循序渐进学习路径初级阶段1-2周理解每种模式的意图和结构实现书上简单示例重点掌握工厂方法、单例、适配器、装饰器、观察者中级阶段2-4周识别模式应用场景重构现有代码应用模式重点掌握抽象工厂、桥接、组合、策略、状态高级阶段持续实践模式组合使用反模式识别性能优化考量掌握访问者、中介者、备忘录等复杂模式6.2 优质学习资源书籍《Head First设计模式》入门首选《设计模式可复用面向对象软件的基础》GoF经典《设计模式之美》实战导向在线课程Coursera Design Patterns伊利诺伊大学Udemy Design Patterns in Java实战项目驱动练习平台Refactoring Guru交互式学习LeetCode设计模式标签题目6.3 个人项目实践建议模式识别练习分析开源项目如Spring、React中的设计模式应用记录发现和思考刻意重构选择自己以前的项目用设计模式重构有明显痛点的模块对比重构前后的可维护性模式混搭实验尝试组合使用多个模式例如工厂方法策略模式记录组合效果和注意事项# 工厂方法策略模式示例 class SortStrategy(ABC): abstractmethod def sort(self, data): pass class QuickSort(SortStrategy): def sort(self, data): return sorted(data) class MergeSort(SortStrategy): def sort(self, data): # 归并排序实现 pass class SorterFactory: staticmethod def create_sorter(algorithm): if algorithm quick: return QuickSort() elif algorithm merge: return MergeSort() else: raise ValueError(Unknown algorithm) # 使用 sorter SorterFactory.create_sorter(quick) result sorter.sort([3,1,4,2])设计模式的学习不是一蹴而就的需要在实际项目中不断实践和反思。我在最初学习时也曾陷入为用模式而用模式的误区后来才逐渐体会到模式是手段而非目的。建议从简单项目开始先写出能工作的代码再考虑用模式优化这样理解会更深刻。