李浩

李浩

随笔小亭

痛风带来的思考

昨晚一罐冰啤酒下去,睡觉时就感觉脚踝隐隐发作,果然早上起床直接下不来地。跟崴脚的感觉十分相似,无法行走,只能坐在一起上滑动,公司上班也去不了了,呆呆得躺在家里,下午疼痛感加剧,整个心思都在左脚的疼痛上,没有其他任何多余的精力去关注其他事情,而此刻的阳台,乃最美人间四月天,春日的微风吹拂着阳台的花儿,温暖的阳光抛洒下来,一切都如此惬意,而我却无心欣赏。 人在健康时,生活中有好多问题,但人在不健康时,生活中只剩一个问题。 我对这句话的理解更深刻了。人是健忘的,在疫情期间、在手术期间,这种感悟其实已经很深刻了,但是病情好转之后,人还是会被日常的琐碎、工作的烦扰搅乱心绪,没有专注的去享受生活本身的美好。 幸福的秘密在于,去享受我们所拥有的,而不是顽固的去追求所没有拥有的。阳光、草木、微风,都是幸福的玩意儿,应尽情的享受。 再等两天,脚完全恢复好了,身体健健康康后,我要以更轻盈的姿态去生活,不纠结他人的看法,不执着别人的认可,关注自己的能力,享受拥有的生后。 还有一个反省,针对咖啡、酒、烟,

By 李浩

设计模式

设计模式之命令模式

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,命令模式也支持可撤销的操作。 来解析这个定义: 1. “将一个请求封装为一个对象”,请求原本是一个方法,现在要封装成一个对象,说明要新增类来完成。 2. “可以用不同的请求对客户进行参数化”,说明是将命令对象作为参数进行传递。 3. “队列”说明需要维护命令多个命令的列表队列。 4. “撤销”说明有命令对象有undo撤销方法。 命令模式在设计模式中,算是一个比较不好理解的模式,很重要的原因是不清楚设计意图,不清楚不用这个模式前有何问题,这个模式带了哪些好处,能解决什么问题。 上一篇状态模式中,看到了状态模式抽离的是状态(属性),向上提成状态对象。有了这个基础,再来理解命令模式就相对简单了。命令模式抽离的是行为(方法),向上提成命令对象。 两者都通过“对象化”来解耦和扩展系统,但解决的问题不同: * 状态模式:处理对象内部状态驱动的行为变化。 * 命令模式:处理行为请求的封装与调度。 💡智能家居遥控器,假设我们有一个智能家居遥控器,可以控制 灯(Light) 和

By 李浩

设计模式

设计模式之状态模式

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。 来解析这个定义: 1. “内部状态”表明对象内部有一个属性来表示状态。 2. “内部状态改变时改变它的行为,对象看起来好像修改了它的类”说明状态改变后对象的行为发生了非常大的变化,不像是同一类的行为。 从目前的分析中似乎无法推导出状态模式的类图结构。 从实际的例子出来,来看看状态模式是如何演进而来。 💡我们有一个文档审批系统,文档有以下状态和转换: 1. 草稿(Draft) → 提交 → 待审批(PendingReview) 2. 待审批 → 批准 → 已发布(Published) 3. 待审批 → 拒绝 → 草稿 4. 已发布 → 撤回 → 草稿 从直觉出发,会使用条件语句实现需求逻辑。 public class Document { private String state = "DRAFT"; // 初始状态为草稿 public void submit(

By 李浩

设计模式

设计模式之代理模式

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。 解析这个定义: 1. “替身”表明在客户端看来,代理类与被代理类是同一类别,对客户端来说看上去没什么区别,依然能够满足诉求。如此可以看出代理类与被代理类来自同一个超类。 2. “控制对这个对象的访问”,能够控制访问,说明前提是能够访问,才能在访问之前做这个限制,即代理持有对真实对象的引用(或能创建它)。 当然可能会质疑,用继承的方式不是也能完成目标吗,用代理类去继承被代理类,然后重写方法,加入控制逻辑。但这违背了"组合优于继承"原则,代理类与被代理类强耦合。 💡我们要开发一个图片查看器,需求如下: 1. 图片加载开销大(从磁盘或网络加载耗时),希望首次显示时才加载(延迟加载)。 2. 某些图片需要权限校验,只有授权用户才能查看。 3. 客户端代码应统一接口,无需关心是直接加载图片还是通过代理。 // 1. 抽象接口(Subject) interface Image { void display(); } // 2. 真实对象(RealSubject)

By 李浩

设计模式

设计模式之组合模式

组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系,使得客户端可以统一处理单个对象和组合对象,而无需关心具体的对象类型。 解析这个定义: 1. “结构型”&“层次关系”,说明此模式针对的对象结构十分典型,对象间的关系有明显的结构特征。 2. “树形结构”,说明此模式就是针对树形结构的对象关系。 3. “部分-整体”,说明组合对象包含了单个对象。 4. “客户端可以统一处理”,客户端可以不关心对象是属于单个对象还是组合对象,表明单个对象和组合对象有相同的超类,而且实现了相同的接口。 在设计业务场景中,有部分整体关系,成树形结构的,有许多,比如: * 文件 vs 文件夹 * 员工 vs 部门 * 评论 vs 回复 从对定义的解析,到树形结构的实现,可以推导出组合模式的结构图。 但,组合模式的关键点,不在于结构图,而在于真正理解这个模式解决的问题,已经为什么要如此设计。 组合模式的核心本质之一,是将递归逻辑从客户端转移到“组合对象”内部。

By 李浩

设计模式

设计模式之迭代器模式

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。 解析这个定义: 1. “聚合对象”,表示对象中有数组、集合、字典等数据类型属性。 2. “顺序访问”,表示模式需提供一个遍历的方式。 3. “不暴露其内部的表示”,表明不想让客户端知道太多内部细节。 综合来看,此模式的设计意图非常明确,将聚合对象的遍历访问职责封装抽离出来。 直接抛出 Iterator 接口和 next()、hasNext() 方法有些“上帝视角”了,让我们抛开预设的实现,从零开始推导如何设计这个“抽离聚合对象访问”的模式,一步步探索最终如何自然演化到经典的迭代器结构。 第一步:明确核心问题 假设我们有一个聚合对象(比如一个自定义集合 MyCollection),内部用数组存储数据。现在需要让外部能遍历它的元素,但不允许直接暴露内部数组。如何设计? 初始代码(暴露内部实现,不符合封装原则): class MyCollection { private String[] data = {"A"

By 李浩

设计模式

设计模式之模板方法模式

模板方法模式定义一个操作中的算法骨架,而将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。 解析这个定义: 1. “算法骨架”,表明是定好了调用多个方法调用的框架顺序。 2. “某些步骤延迟到子类”,延迟到子类说明框架由超类定义,“某些步骤”表明只是部分交由子类自定义,而还有一部分是由超类已经定义好了,由此可以表明超类必须是抽象类,而非接口,“某些步骤”相应的就是抽象方法。 💡假设我们有一个电商平台的支付系统,支付流程通常包含以下固定步骤:验证支付参数、调用支付网关、记录支付日志、通知支付结果,其中,第2步"调用支付网关"因支付方式不同而实现不同,其他步骤则可以复用。 // 抽象支付类 - 定义支付流程模板 public abstract class PaymentProcessor { // 模板方法(final防止子类修改流程) public final void processPayment(double amount, String orderId) { validate

By 李浩

设计模式

设计模式之外观模式

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 解析这个定义: 1. “统一的接口,用来访问子系统中的一群接口”,如果不这么做之前,当多个客户端时,每个客户端都需要实现调用一群接口的逻辑,实现重复且复杂。且客户端耦合每个子系统的具体实现,不符合开闭原则。用一个统一接口封装一群接口,客户端只需要依赖一个类的一个接口即可。 2. “高层接口”,说明外观类是在子系统之上,这是一个架构结构上的变化。 💡现代计算机的启动过程涉及多个硬件组件(如CPU、内存、硬盘等)的协同工作,每个组件都有自己的初始化逻辑。 没有外观模式时的实现: // 子系统类(与之前相同) class CPU { public void start() { System.out.println("CPU启动"); } } class Memory { public void load() { System.out.println("内存加载&

By 李浩

设计模式

设计模式之适配器模式

适配器模式将一个类的接口,转换成客户期待的另一个接口。适配器让原本接口不兼容的类可以合作无间。 解析这个定义: 1. 客户端依赖的接口TargetInterface,无法用现有的类adaptee实现,需要增加一个新类adapter来包装实现,但客户对此应透明,感知不到,如何才能感知不到,就需要adapter类继承或实现客户端依赖的类或接口,这样依赖抽象编程,就可以在子类去完成适配转换。 2. 适配类adapter要能实现客户要求的能力,如何做到,有两种方式,一种是直接关联一个adaptee对象,调用对象的目标方法;另一种方式是直接通过继承,自动拥有父类的目标方法。这两种实现方式称为对象适配器和类适配器。对象适配器思维更加自然,更为常用,特别是对于需要适配多个类接口时,一些语言是不支持多重继承的,无法用类适配器完成,只能应用对象适配器。 对象适配器还是类适配器,只是如何获取被适配对象的目标功能的两种不同方式而已,很多人常常采用强记的方式学习设计模式,死记类图,其实完全没有必要,更重要的事,理解模式本身的意图本质,和实现目标的思考过程。类图会依据继承或实现画法发生变化,往往让初学

By 李浩

从郎咸平批评认知看职场祛魅

郎咸平在回复一个提问“月入五千和月入五万”在认知上有什么差别时,本以为他会从认知维度高谈阔论来论证,结果却是对提问者好不委婉的训斥,他说: “你们和送外卖的在认知上没什么区别,在我看来没有区别,你们一样啥也不懂,唯一的区别是你过了哪条线,才有了参与的机会。恰好你还干得不错,可能是这个因素,也可能是那个因素,就是综合原因,才走到了现在”。 这句话乍一听有点刺耳,甚至带着点精英主义的傲慢,但仔细琢磨,却戳中了职场和社会竞争里最隐秘的真相——很多时候,你需要先拿到上桌门票,才有机会参与游戏。 在职场中,要进行祛魅职场,那些“上桌的人”,未必比你强,只是比你早一步摸到了入口。 我花了很长时间才想明白一件事:那些坐在高位的人,那些在会议上侃侃而谈的“专家”,那些手握资源、头衔光鲜的“成功者”,其实并没有想象中那么不可企及。他们未必比我聪明,未必比我更懂业务,甚至未必比我更努力——他们只是比我早一步摸到了某个入口,或者恰好踩中了某个契机。 这个认知让我彻底放下了对“权威”的盲目敬畏。我开始明白,职场和社会竞争的本质,不是能力的绝对比拼,而是一场关于“规则、

By 李浩

随笔小亭

从《长安的荔枝》看职场

《长安的荔枝》是马伯庸以"一骑红尘妃子笑"为背景创作的历史小说,通过小人物李善德运送鲜荔枝的曲折经历,折射出许多值得深思的职场生存法则。结合这个故事,谈谈几点职场体会: 1. "领导一句话,下属跑断腿"的职场现实 李善德接到"从岭南运鲜荔枝到长安"这个不可能任务时,深刻展现了职场中"目标自上而下传导,执行压力由基层承担"的常态。体会是: * 上级的决策往往不考虑执行细节 * 中层需要将模糊目标转化为可执行方案 * 执行层要在资源有限的情况下创造奇迹 2. "流程合规"与"结果导向"的博弈 李善德在遭遇衙门推诿时悟到:"做官之道,其实就三句话:和光同尘,雨露均沾,花花轿子众人抬。"这揭示了职场潜规则: * 过分坚持原则可能寸步难行(

By 李浩

设计模式

设计模式之单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点。 咋一看这个定义,先解决一个疑惑,什么时候需要保证类只有一个实例。在实际生产场景中,有许多这样的实例,大多出于两个目的,防止资源浪费和保证数据一致性。比如常见的数据库连接池、线程池、日志记录器、缓存实例、配置信息实例等通常只需要一个实例来管理资源,能够节省开销,避免多实例带来的数据不一致。 明确了实际用处后,再来解析定义: 1. “确保一个类只有一个实例”,类是如何实例化的,通过调用构造函数,谁调动构造函数谁就能创建实例,确保只有一个实例,就是要控制构造函数被调用的权限,防止外部代码通过构造函数或其他方式创建多个实例。 1. 私有化构造函数:将类的构造函数设为私有(或受保护),禁止外部直接调用构造函数创建实例。构造函数私有了,构造出的唯一实例也必须是本类自身维护了。 2. 控制实例化过程:在类内部管理实例的创建,确保只有一个实例存在。 2. “全局访问点”,为了让外部代码能够方便地获取这个唯一的实例,使用静态方法即可。 💡日志记录器(Logger),应用程序的多个模块需要记录日志。日志记录器应该是全局唯

By 李浩