ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GOF设计模式笔记:从背模式到用模式的实战指南

GOF设计模式笔记:从背模式到用模式的实战指南 GOF笔记这四个字对写过几年代码的人来说差不多是一种暗号。听到就能想起那本灰色封面的《设计模式》想起里面23个经典模式想起自己年轻时捧着它背类图的日子。我刚入行那会儿把23种模式的UML图抄了整整两本笔记本面试时倒背如流可真到写业务代码时满脑子只剩一种模式——复制粘贴。真正的转折点出现在我工作第三年。那段时间我在重构一个满是if-else的订单系统改一处牵三处测试用例越补越多代码却越改越乱。某个周五的深夜我盯着屏幕上那段二十层嵌套的switch发呆脑海里突然冒出GOF里的一句话“要封装变化。”那一瞬间像被人拍了后脑勺一样——原来我一直没读懂这本书我只是把它的骨架背下来了。也是从那时候起我开始重新做一份属于自己的GOF笔记从“每个模式叫什么、类图怎么画”变成“这个模式到底在解决什么、什么时候该用、什么时候千万别用”。这篇文章就是那份笔记的整理版。它覆盖23种设计模式的整体框架、几个高频模式的核心细节、大作业和期末复习的应对思路以及我在真实项目里的选型体会。无论你是正在准备设计模式考试的学生还是工作几年想补上这块短板的工程师都能在这篇里找到可以直接拿去用的东西。1. 为什么工作多年后我才真正读懂这本GOF经典1.1 从“背了23个名词”到“看懂代码的呼吸”我第一次读GOF是在大学说实话读得很痛苦。满书都是抽象类和协作图每个模式都像在绕口令我只能用最笨的办法——把类图抄到笔记本上把模式名和UML图对应起来硬背。考试前我确实能默写单例和工厂的类图但你要是给我一段实际的烂代码问我“该用什么模式改”我脑子里是一片空白。原因现在回头看很明白我当时把设计模式当成了一套“标准零件清单”以为做软件就像拼乐高遇到某个形状就该用某个零件。但GOF整本书从头到尾只在讲一件事——如何封装变化。几乎每个模式的前几页都在回答同一个问题这段代码里什么东西是容易变化的把这个容易变化的东西抽出来让稳定的部分依赖一个稳定的接口这就是设计模式最底层的套路。1.2 设计模式其实是软件界的“成语词典”打个比方设计模式就像中文里的成语。你当然可以用大白话把“塞翁失马”的意思完整讲出来但你说“塞翁失马焉知非福”四个人就能听懂一整个故事。代码里的模式名也一样你说“这里我打算加一层Adapter”同事立刻就知道你是要改造接口兼容性而不是在业务逻辑里打补丁。模式名是一种高密度的沟通语言。但成语用多了会变成“掉书袋”。我见过有人在一个二十行的类里硬塞五种设计模式看起来每个名字都很高级读代码的人却想骂人。设计模式的正确用法是在合适的变化点上用合适的抽象力度——不是所有地方都需要模式模式本身也分轻重缓急。1.3 这本笔记到底适合谁、该怎么读我后来把这份笔记翻来覆去改了好几版也慢慢摸清了不同读者的读法。学生党尤其是要交设计模式大作业、准备期末考的可以把重点放在第2、3、4、5章的分类和模式辨析上这直接对应考试里最常见的“请分析某段代码用了什么模式”“请比较策略模式和状态模式的区别”这类题目。大作业设计可以重点看第6章我整理了一套“先找变化点再选型”的思路。初级工程师重点看第3、4、5章的实战部分和代码示例这些模式是你日常写业务代码时最高频遇到的。看懂之后X你的代码Review会被同事少挑出很多毛病。资深开发者可以直接跳到第6、7章那里有我做架构选型时踩过的坑和反思希望能帮你少走一点弯路。2. 先把23种模式装进一张地图分类不是拿来背的2.1 三种分类的本质创建、结构、行为到底在管什么GOF把23种模式分成三大类创建型、结构型、行为型。很多人背分类时只记住了名单却没想过这个分类维度本身的价值是什么。我的理解是这三类模式分别对应对象生命周期的三个阶段以及每个阶段最核心的变化点。创建型模式管的是“对象是怎么来的”。它要屏蔽的变化点是直接new对象还是通过某种间接方式创建创建过程是简单还是复杂需不需要复用已有对象结构型模式管的是“对象之间怎么组合”。它要屏蔽的变化点是多个类如何拼出一个更大的结构是继承、是组合、还是加一层包装行为型模式管的是“对象之间怎么协作”。它要屏蔽的变化点是一个行为或算法由谁来执行、怎么执行、执行时怎么跟其他对象通知状态明白了这个维度你再去看任何一个具体模式都会先问一句这个模式是解决“怎么创建”“怎么组合”还是“怎么协作”定位清楚之后它的核心思想基本就出来了一半。2.2 模式之间的“亲戚关系”它们从来不是孤立的笔记里我专门画了一张“亲戚关系图”把经常搭配出现的模式用线连起来。这里说几个最典型的搭配。工厂 单例是最经典的。单例负责“全局只有一个实例”工厂负责“创建逻辑集中管理”。很多框架里配置管理器就是单例而它又通过简单工厂去创建不同类型的配置对象。两个模式是天然搭档。策略 工厂也很常见。策略定义“算法族”工厂负责“根据条件选择具体策略”。你可以在工厂里维护一个Mapkey是策略类型value是策略对象彻底消灭一大堆if-else。我在支付系统里就是这么干的。状态 命令在游戏里经常一起出现。状态模式管理“角色当前处于什么状态”命令模式管理“一个动作可撤销、可重放”。两者的核心都是“把一个行为封装成对象”一个侧重状态流转一个侧重行为本身。装饰器 适配器容易被搞混。它们都是“包装”一个对象但目的完全不同适配器是“接口不对翻译一下”装饰器是“接口不变增强功能”。理解了这个区别后面看代码就能少踩很多坑。2.3 创建型模式的核心差异对照表创建型模式一共五个单例、简单工厂、工厂方法、抽象工厂、建造者、原型。前两个严格来说不是GOF原始23种里的但实际开发中太常用了我笔记里把它们放进来了。下面这张表是我复习时经常看的对照表模式解决的核心问题一句话类比常用场景单例 (Singleton)全局唯一实例全公司只有一个CEO配置管理、日志、连接池工厂方法 (Factory Method)延迟创建到子类每个分店自己决定做什么菜框架里让子类决定创建哪种对象抽象工厂 (Abstract Factory)创建一整套配套对象一个品牌的全套家电UI主题切换、多数据库支持建造者 (Builder)分步骤构造复杂对象组装一台电脑一步一步来复杂参数对象的构造原型 (Prototype)克隆已有对象复印机直接复印对象创建成本高时复制自身这张表不用全背下来关键是理解每个模式的“变化点”。比如单例的变化点是“个数”工厂的变化点是“类型”建造者的变化点是“步骤”原型的比变化点是“拷贝成本”。理解到这一层考试时给你一段代码你就知道该往哪个方向去分析了。3. 创建型模式笔记单例、工厂、原型里的那些坑3.1 单例不是“全局变量”的遮羞布单例应该是最被滥用的设计模式。很多初学者一看到“某个类只需要一个实例”就条件反射式地写上GetInstance()。但单例本质上还是个全局状态你用它的同时也把测试的难度拉高了——所有依赖这个单例的代码都很难被替换成mock对象。我工作中真正会用单例的场景只有几个全局配置管理器、日志器、线程池、连接池。这些对象的共同点是你确实不希望它们被复制多份而且它们本身不包含业务状态。C里我推荐用Meyers Singleton也就是函数内的静态局部变量class ConfigManager { public: static ConfigManager instance() { static ConfigManager inst; return inst; } std::string getConfig(const std::string key); private: ConfigManager() default; ConfigManager(const ConfigManager) delete; ConfigManager operator(const ConfigManager) delete; };C11之后局部静态变量的初始化是线程安全的所以这个写法既简单又不存在双重检查锁那些破事。Java里我建议优先用枚举单例Effective Java里说得很透彻——枚举天然防反射、防序列化破坏还能保证只有一个实例。最大的坑是你把单例当成万能药在一堆业务服务里塞单例对象最后整个项目一堆互相纠缠的全局状态改起来像拆炸弹。记住能用依赖注入传对象的情况下就别用单例。3.2 工厂家族从简单工厂到抽象工厂的演进逻辑工厂模式的演进逻辑本身就是一个“逐步应对更复杂变化”的过程。简单工厂最朴素。一个静态方法根据switch分支new出不同的子类。优点是好写缺点是每新增一个产品就要改工厂类违反了开闭原则。但是如果你的产品类型几乎不会变简单工厂反而是最佳选择因为过度设计也是坏味道。工厂方法模式把“创建”动作延迟到子类。父类定义业务框架子类决定具体创建哪个产品。这在你做框架设计时特别有用——框架把骨架定好使用者只需要继承并重写一个工厂方法。举个我实际用过的例子一个报表导出框架public abstract class ReportExporter { public void export() { // 公共逻辑准备数据、校验 Exporter exporter createExporter(); exporter.write(); } // 子类决定导出成PDF还是CSV protected abstract Exporter createExporter(); }抽象工厂更进一步它创建的不是“一个产品”而是“一整套产品族”。比如UI系统的主题暗色主题会同时创建暗色按钮、暗色窗口、暗色滚动条这些产品之间是配套的。你不能让暗色按钮配上一个亮色滚动条。抽象工厂的价值就是保证“成套”。3.3 原型模式的深拷贝陷阱原型模式适合“对象的创建成本远大于拷贝成本”的场景。比如一个包含了大量初始化计算、数据库读取的复杂对象你每次想要一个“差不多的对象”时直接clone比重新new一个再初始化快得多。但我必须提醒原型模式的坑基本都在拷贝上。C的拷贝构造函数默认是浅拷贝Java的clone()默认也是浅拷贝一个不小心就把指针或引用的成员共享了改一处全盘受影响。我踩过一次深刻的坑某个地图编辑工具里的地块对象用了原型模式克隆地图图块浅拷贝导致多个图块共享同一份纹理资源后来一个地块改了颜色旁边几十个地块全部跟着变色。那次之后我定了条规矩原型对象的成员变量里如果有指针、引用、集合这类资源必须做深拷贝并且一定要写测试验证对象之间的独立性。ChatGPT原型模式还有一个进阶用法——原型注册表。维护一个id到原型对象的映射根据字符串id直接拿原型去克隆。这样当你需要动态创建新类型的对象时不需要写一长串switch只要往注册表里注册一个原型实例就够了。有点像“打印店有各种模板你要哪个模板报个名就行不用每次都重新排版”。这是原型模式在很多游戏引擎里被大量使用的原因。4. 结构型模式笔记让系统在不拆墙的前提下扩展4.1 适配器老接口和新SDK之间的翻译官适配器模式是我在现实项目中用得最多的结构型模式没有之一。几乎每个项目都会遇到“老接口不想动新SDK接不上”的尴尬。我处理过的典型场景是支付接口系统里原本已经定义了PaymentProcessor接口里面有pay()方法但新接入的第三方支付SDK类叫WechatPayClient方法叫processAmount()参数类型还对不上。不改老接口、不改新SDK那就写个适配器public class WechatPayAdapter implements PaymentProcessor { private WechatPayClient client; public WechatPayAdapter(WechatPayClient client) { this.client client; } Override public void pay(Order order) { client.processAmount(order.getAmount(), order.getTitle()); } }这个模式没有任何玄学就是一个翻译层。但有一个设计细节值得说适配器应该尽量放在“消费方”这一侧也就是不要让老系统去迁就新SDK的尾部接口而要写一个适配器把新SDK翻译成老系统已经熟悉的语言。这样老系统完全感知不到新SDK的存在以后换掉这个SDK也只是删掉一个适配器的事——这正是依赖倒置的一种体现。4.2 装饰器比继承更灵活的水平扩展装饰器模式解决的核心问题是类很多功能组合也很多如果用继承去组合功能会发生灾难性的类爆炸。五个基础功能两两组合就是一堆子类。Java IO流的设计模型是最经典的教科书式装饰器例子。InputStream in new BufferedInputStream(new FileInputStream(test.txt));这里的FileInputStream是核心组件BufferedInputStream是装饰器它加了缓冲功能却没有改变FileInputStream的“读字节”接口。你看扩展功能没通过继承而是通过一种“套娃”的方式一层层包起来。我工作里最常用的装饰器场景是权限校验和日志记录。比如某个服务接口要加一个“登录校验”流程上你是直接改原业务类还是给原业务类套一个装饰器装饰器的做法是写一个AuthDecorator它实现同样的接口但方法里先做校验再调被包裹的业务对象。这样业务类保持纯净校验逻辑可以复用、可以组合、可以随时开关测试起来也友好很多。有一个容易踩的坑装饰器要保证接口一致如果你在装饰器里改了方法的签名或返回类型那它其实已经变成一个适配器了职责就乱了。所以用装饰器之前先停下来问自己我到底是要“保持原接口增强功能”还是“改造接口让两边能对接”前者用装饰器后者用适配器。4.3 代理模式与延迟加载代理和装饰器长得很像也都是“包装对象”但目标又不一样装饰器是为了增强功能代理是为了控制访问。代理最常见的用途是延迟加载。比如一个编辑器开了个超大图片文件你不想在启动时就把整张图读进内存而是等滚动到那块画布区域时再真正加载。这种“虚拟代理”可以先显示一个占位框等需要时再调真正的加载逻辑。早期那些图片懒加载的库核心思路都是代理模式。代理还有保护访问、权限控制、远程代理RPC这些用途。Java的静态代理让我不舒服之处在于每个类都要手写一个代理类太累赘。后来在项目里用上了动态代理一个拦截器就能处理一类方法调用代码量骤减。不过我要提醒一句代理层不是一个随意加的地方。我见过有人给每个Service都套一层代理做日志结果代理嵌套出了小十层出问题时日志和业务流程混在一起排查问题花了一天半。代理加在“方法级、模块级”的边界上才是合理的比如整个RPC调用的入口、Controller接收请求的入口而不是每个类都去套一次。5. 行为型模式笔记把变化的行为抽离成对象5.1 策略模式把if-else变成选择题行为型模式里我最推荐先学策略模式因为它是消除业务代码里大量if-else的利器而且思路非常好懂。我举一个积分折扣的例子。一个商城系统不同用户等级有不同的折扣逻辑不用策略模式的时候代码长这样double getDiscountedPrice(Order order, User user) { if (user.getLevel() VIP) { return order.getAmount() * 0.8; } else if (user.getLevel() MEMBER) { return order.getAmount() * 0.9; } else { return order.getAmount(); } }这种写法在业务规模小的时候没什么问题但一旦折扣逻辑变复杂——加一个“生日月打折”“双十一再叠加满减”之类的规则这个if-else就会膨胀成一个巨无霸函数每次调整规则都得小心翼翼地改这里。用策略模式的做法是定义“折扣算法”这个策略接口每种规则一个实现类然后在用的时候根据用户等级从容器里取对应的策略public interface DiscountStrategy { double calc(double amount); } public class VipDiscount implements DiscountStrategy { public double calc(double amount) { return amount * 0.8; } } public class MemberDiscount implements DiscountStrategy { public double calc(double amount) { return amount * 0.9; } }策略模式的核心收益是把“变化的行为”抽出来变成对象让策略可以独立演化、自由组合、单独测试。但别把所有零散逻辑都套路化只有那些确实在多个版本之间会变化的行为才值得这么抽象。5.2 观察者模式从GUI事件到消息队列的内核观察者模式解决的是“一对多”的通知问题一个对象状态变了多个其他对象要跟着做出反应。最经典的例子是GUI里的按钮点击事件。按钮被点击监听它的N个监听器都要收到通知。Java里的ActionListenerC#里的eventC里的信号槽本质上都是观察者模式的实现。在游戏开发里观察者模式也极其常见。角色获得了经验值经验条UI要更新、成就系统要判断是否解锁成就、音效系统要播放升级音效这三个系统根本不想关心“谁触发的事件”它们只关心“经验值变化了”。你让角色模块逐个通知它们那角色模块就得知道所有模块的存在耦合度就失控了。用观察者模式角色模块只负责发事件三个系统各自订阅事件互不感知。现在很多系统把观察者模式发展成了事件总线和消息队列但核心思想依然是发布者不关心订阅者是谁订阅者不关心事件从哪里来。有一个要注意的坑事件回调里的异常处理。观察者里的某个监听器如果抛了异常会不会中断其他监听器Java里如果用for循环通知监听器一个监听器抛异常后面的监听器就全挂了。我习惯在事件总线的通知函数里加try-catch确保某个监听器出错不影响其他监听器。5.3 状态模式游戏里角色状态机的实现思路状态模式是行为型模式里比较容易被误解的一个。它和策略模式结构上长得很像——都是一个接口多个实现类但意图完全不同策略模式里各个策略是“平级、可切换”的算法状态模式里各个状态是“有流转关系”的而且流转通常由事件和当前状态共同决定。游戏里最常见的例子就是角色状态机。角色有站立、走路、跳跃、攻击这些状态。站立时按前进键会变成走路走路时按跳跃键会变成跳跃但攻击中按跳跃键可能不允许切换。如果用一堆bool去管理代码很快会变成一团乱麻。状态模式的做法是把每个状态都封装成一个类class PlayerState { public: virtual ~PlayerState() default; virtual void handleInput(Player player, Input input) 0; virtual void update(Player player) 0; };IdleState、RunningState、JumpingState各一个类每个类里只处理“在这个状态下收到某个输入时该干嘛”。角色本身持有一个当前状态的指针每次输入事件来了就调currentState-handleInput(*this, input)状态就可以自行决定要不要切换到另一个状态。这套思路不仅用在游戏里。我曾经把一个设备控制程序里的“待机、校准、运行、报错”四种设备状态也做成了状态模式业务代码直接从一堆flag和if里解脱出来设备状态的流转规则也变得一目了然。写状态模式最难受的是“状态过多”的时候。如果状态有二十来个类文件也会膨胀得很吓人。这时候可以引入状态表用一张二维表去配置“当前状态输入事件下一状态”把流转规则从代码变成数据反而比写二十个类更好维护。6. 设计模式在大作业、期末和真实项目里的正确打开方式6.1 设计模式大作业先找变化点再选模式热搜词里有“设计模式大作业”我就知道很多人在为这个头疼。我当过几年助教看过几百份设计模式大作业最典型的问题是为了用模式而用模式结果整个系统画蛇添足。我建议你按这几步来设计一个大作业第一步确定系统的核心业务场景想清楚有什么东西是可能变化的。比如做一个电商系统你可能会想商品类型可能会变、支付方式可能会变、折扣规则可能会变。这三个就是“变化点”。第二步针对每个变化点用最精简的模式去应对。支付方式变化可以用策略模式或者工厂模式折扣规则变化可以用策略模式订单状态流转可以用状态模式商品创建复杂可以用建造者模式。第三步把模式的选型写进设计文档里说明为什么选这个模式、它封装的到底是什么变化。评分老师最喜欢看到这种“有依据的选择”比堆十个模式强一百倍。第四步画清UML图按GOF笔记里的图例画出类图和关键的时序图把模式之间的关系展示清楚。大作业的打分重点通常不是“你的模式用得多么炫”而是“你的系统里模式是否解决了真实问题”。一个只用三个模式但用得贴切的项目比一个硬凑六个模式但逻辑混乱的项目得分高得多。6.2 期末考试的模式辨析题怎么答才能拿分期末考最常考的题型我总结一下给一段代码让你分析用了哪种模式或者让你比较两个相似模式的区别。前者靠你对模式特征的敏感度后者靠你对“意图”的理解。面对“这段代码用了什么模式”我的判断顺序是先看对象是怎么创建的。如果是通过一个工厂类、一个抽象方法、一个clone方法创建的那大概率是创建型模式。再看对象有没有被包装。如果外面包了一层接口不变是装饰器接口变了是适配器控制了访问是代理。最后看行为怎么协作。如果是一个算法被抽出成了独立对象是策略如果是一系列状态自动流转是状态如果一个对象变化通知了多个对象是观察者。比较类题目的高频对比如“策略 vs 状态”“策略”是平行的算法客户端主动选择而“状态”是状态机驱动对象内部根据事件自发流转。“装饰器 vs 代理”装饰器增强功能接口不变代理控制访问可能延迟创建、可能加权限、可能远程调用。说一个答题技巧答辨析题时先说共同点再说核心区别最后用一个例子验证。比如“两者都是对对象进行包装的结构型模式但装饰器是增强功能代理是控制访问。以日志功能举例日志装饰器在原接口里加日志而代理可以在不调用原方法的情况下直接返回控制访问权限。”这样分段写分基本就拿稳了。6.3 真实项目里最怕的不是没有模式是“反模式”真实项目里最让人头痛的其实不是“模式不够用”而是“模式被用成反模式”。我见过所谓“万能Service”一个类三千行里面什么都有却要给每个客户端的请求都走一遍它的handle方法——这是反模式因为它本质上是一种只有上帝才能维护的全局状态。最典型的反模式我还想提一个——“隧道效应”表面上用了好几个设计模式但每个模式都没有真正起到抽象作用代码反而更多了写起来更绕了。比如有人学了策略模式把原本一个函数写清楚的代码拆成五个类加一个接口逻辑没变简洁反而更难读。这就是过度设计。怎么判断自己是不是过度设计了我有一个很简单的标准删掉这个模式代码会不会变得更难维护而不是更容易如果答案是“删掉它反而更像一坨屎”那这个模式就该留着如果答案是“删掉它代码更清爽”那它就是在粉饰混乱。这个标准我在代码Review里反复用很好使。7. 我整理GOF笔记的方法画图、重构、回译7.1 画图优先亲手画过类图才算真的读懂一个模式读设计模式最忌讳只看文字。光看文字你会觉得“好有道理”但下次用到的时候依然无从下手。我的经验是每个模式都要亲手画一遍类图和相关对象的时序图。画类图的目的不是练习UML语法而是逼你理清“谁依赖谁、谁实现谁、谁组合谁”。你画单例模式下只是画了一个类带一个私有静态实例但你要是画策略模式就必须想清楚Context类和Strategy接口之间是组合关系具体策略之间是兄弟关系时序上Context先调用策略接口再调用具体实现。画的时候我还会标上接口和实现类的关键方法名。这样当我在真实项目里需要想“哟这里是不是可以用策略”时脑子里立刻会浮现那张图画。记忆效果比背书好十倍。7.2 用真实代码重构来验证理解而不是抄书上的例子抄书上的例子最大的问题是例子都是“设计出来”的跟真实业务的复杂度完全不同。所以我看完一个模式后会刻意回公司项目里找一段“味道比较重”的代码试着用这个模式去重构它。比如我当时学命令模式立刻就盯上了项目里那几个全是if-else的操作分发函数。我花了一个下午把每个操作封装成命令类然后塞到一个命令队列里让操作支持回滚和重放。重构完之后我发现代码跑得更稳了而且看代码的人一眼就明白业务意图。那次“用真代码练手”的收获比我看十遍书都大。如果暂时没有真实代码可以练也可以自己造一个“半真半假”的小项目去练手比如做一个简化版RPG战斗系统把策略、状态、观察者、装饰器一次全用上。关键在于模式要“用出去”而不是“留在笔记里”。7.3 “回译法”才是检验理解的最狠武器我检验自己有没有真正理解一个模式的方法是把它用大白话讲给一个不太懂技术的人听。讲不通说明我自己还没吃透。我把这个方法叫“回译法”。比如说策略模式我讲过一版是“就像去餐厅吃饭菜单上每一种菜都是独立的你点哪个就厨房做哪个厨房不用知道所有菜的做法只需要按你选的菜单执行。”这就把“客户端选择策略、策略各自独立、不会互相影响”说清楚了。观察者的回译版本是“你在公众号上点了关注作者一发文你立刻就能收到通知。而作者根本不需要知道有没有你这个人他只需要在写完文章后点一个‘发布’按钮。”状态模式则可以说是“红绿灯自带一套规则绿灯过一段时间自动变黄再变红司机看到什么灯就做什么反应。灯的状态自己流转不需要交通警察在旁边手动切换。”这种类比能让我从“背定义”切换到“理解意图”考试、写代码、评审带新人都用得上。你在做自己的笔记时也一定要试着给每个模式写一句属于你自己的大白话版本写不出来就说明还需要再看一遍。7.4 最后一个小习惯每页笔记都留一栏“什么时候别用”最后说一个我记笔记的小习惯我给每个模式都留了一栏“什么时候别用”。这一栏的价值到我后来做技术评审的时候才真正体现出来。比如单例那一页“别用”栏里写着不要为了全局方便就用单例不要在有复杂业务状态的服务里用单例不要在测试里依赖单例。原型那一页“别用”栏里写着如果对象的浅拷贝代价很低直接用new更简单如果没有深拷贝能力千万别用原型。这一栏比模式本身的定义还珍贵。因为我发现设计模式学到后面真正考验功力的不是“用对模式”而是“在各种各样的实际场景里果断地放弃模式”。一个工程师设计能力到没到位就看他在“不该用”的场景里能不能说出清楚的道理。所以如果你的GOF笔记只能留一栏我建议你留“什么时候别用”这一栏。它能让你从“模式的崇拜者”变成“模式的主人”。
返回列表