重温HeadFirst设计模式

本文深入探讨了软件设计中的几种重要模式,包括策略模式、观察者模式、装饰者模式、工厂模式、单例模式、命令模式、适配器与外观模式、模板方法模式以及迭代器与组合模式。策略模式通过封装算法族,使客户能灵活选择算法;观察者模式实现了一对多的依赖关系,允许对象在状态变化时通知其他对象;装饰者模式动态增加对象功能,提供了比继承更灵活的扩展方式;工厂模式则关注对象的创建,通过工厂方法或抽象工厂模式实现对象实例化的解耦;单例模式确保类只有一个实例,提供全局访问点;命令模式将请求封装为对象,支持撤销操作;适配器模式和外观模式分别用于接口匹配和简化复杂接口;模板方法模式定义算法骨架,允许子类定制具体步骤;迭代器模式和组合模式则分别提供有序访问聚合对象和构建树形结构的方法。文章还强调了设计原则,如依赖倒置、开闭原则等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.策略模式

定义: 策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

实例:鸭子的飞行行为委托给行为类实现,鸭子在构造时需要传入flyable接口的实现类实例,还可以通过set方法改变,自己的fly方法委托给行为类实现,“有一个”可能比“是一个”更好,更灵活;多用组合,少用继承。

2.观察者模式
定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都会收到通知并更新。

角色:Observer观察者,Observerable被观察对象

实例:weatherData类有modified()方法,当天气数据变化时该方法中的代码会被调用。weatherData类中维护一个公告板接口类的集合,同时对外提供订阅和取消订阅两个接口。在modified方法中遍历调用公告板接口类的update(),将所有订阅的公告板数据刷新。

好处:当新增公告板时,不需要修改weatherData类,只需要让公告板使用registerObserver()订阅weatherData即可。

3.装饰者模式

定义:装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

实例:购买咖啡时,可以加入各种调料,如:蒸奶、豆浆、摩卡等,加入调料后咖啡的cost()方法返回的价格就要加上调料的价格。这些调料有无数种组合,如果把每种组合的咖啡都写单独的类,将会类爆炸。用装饰者模式可以解决,把咖啡、蒸奶、豆浆、摩卡都当成饮品类(Beverage),都有cost()方法,该类有带参构造方法:new Beverage(new Beverage());构造方法中传入的对象是被包装的对象,包装类在计算cost()时将自己的价格加上被包装类的价格。

角色:装饰者和被装饰者;该两个类实现了同样的类型,在用户看来,区分不了该类是不是被包装过。装饰者的方法是在委托给被装饰者后加入了自己的改造。

4.工厂模式

a.简单工厂,将创建对象放在工厂类中,如果工厂类中的方法是静态方法,那么就叫静态工厂。静态工厂使用方便,缺陷是不能通过继承改变创建方法的行为。
简单工厂的好处:当有多个客户使用简单工厂时,如果需要修改创建的对象,在简单工厂这一处修改即可。

b.工厂方法模式

定义:工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类。

实例:PizzaStore的orderPizza()对外创建披萨需要有多个步骤,首先createPizza()得到pizza对象,然后pizza.prepare()、pizza.bake()、pizza.cut()、pizza.box(),然后返回该pizza给客户。不同工厂风味的披萨只是createPizza()得到的pizza对象不一样,而后续的prepare等方法需要都保持一样。故定义一个抽象的工厂类:PizzaStore,包含抽象方法createPizza(String type), 在其orderPizza()方法中的第一步就调用了该抽象方法,然后再调用pizza.prepare()、pizza.bake()、pizza.cut()、pizza.box(),将pizza对象返回。 新建工厂如纽约工厂,NYPizzaStore需要实现createPizza(String type)这个抽象方法,其orderPizza()就会使用该字类的createPizza()抽象方法的具体实现。而其他流程如prepare()等等都不需要也无法改动。工厂方法模式就通过在工厂方法中调用抽象方法来达到将类的实例化推迟到子类的。
这里也是依赖倒置原则的很好体现: PizzaStore是高层类,不应该依赖于具体的NYPizza或者是ChicagoPizza,而是只依赖于他们的高层Pizza。

c.抽象工厂模式
定义: 抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

实例: 在Pizza类的prepare()方法中准备pizza的原料,不同风味的原料不同;如NYPizza需要NY面团、NY酱料和NY奶油,而ChicagoPizza需要Chicago面团、Chicago酱料和Chicago奶油。现在的做法是:在Pizza抽象类构造方法中有IngredientFactory抽象类做为参数,prepare方法中就使用该抽象类的系列抽象方法dough = factory.createDough(); sauce = factory.createSauce();cheese = factory.createCheese();而不同的pizza子类,如NYPizza传入的原料工厂就是原料工厂子类NYIngredientFactory。
抽象工厂和工厂方法的区别: 抽象工厂使用对象的组合实现,而工厂方法使用类实现。

比较点抽象工厂工厂方法
实现方式客户端在上层抽象中自身组合了抽象工厂的实例,使用对象调用抽象工厂的生产方法抽象类中的其他方法先使用了该由子类实现的抽象方法,这样子类实现该抽象方法时,就完成了将具体实现推迟到子类实现的目标
作用创造一族相关的产品将产品的具体实例化推迟到子类中完成

5.单例模式
定义:确保一个类只有一个实例,并提供一个全局访问点。
实现思路: 私有化构造方法,提供静态公有方法getInstance。有懒汉式和饿汉式两种实现方式。懒汉式在多线程下会不安全,可以用加锁保证,但是加锁后代码的性能低下,用双重检查可以提高性能。属性上记得加上volatile关键字

6.命令模式
定义: 将"请求"封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
实现思路: 定义一个Command接口,该接口有public void execute();在接口的实现类中,将需要被执行的代码放在execute()中。当客户想要执行这段代码时,只需要拿到这个Command对象,然后调用execute()即可,客户不需要知道代码的细节。将请求封装成对象,好处是可以当作参数一样传递,可以放入队列,还可以用日志记录(用java的对象序列化将命令对象记录到文件中)。
若将命令对象放入了队列中,我们可以批量运行队列中的命令,达到宏命令的效果。
java中的线程就是使用了命令模式: new Thread(Runnable run);

7.适配器与外观模式

a.适配器模式
思路:当客户需要一个 A 类型的对象,而我们只有 B 类型对象时,我们可以创建一个 A 类型的子类 C,C 把 B 组合进去了,C 实现了 A 所需要的方法,而这些方法又是委托给他组合的 B 实现的。

b.外观模式
目的:将复杂的多个接口使用简单的少量接口封装起来,其内部实现对多个接口的调用,而不对外暴露。

8.模板方法模式
定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
实现思路:通过抽象方法占位的方式将算法步骤封装进框架中,由子类对每个步骤的细节进行填充。

9.迭代器与组合模式

a.迭代器模式
定义: 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
实现思路: 对于一个存放多个相同类型元素的数据结构,将其封装起来,变成 Iterable 类型,对外仅暴露 hasNext() 和 next() 接口让外部访问元素。

b.组合模式
定义: 组合模式允许你将对象组合成树形结构来表现“整体 / 部分” 层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

  1. 状态模式
    定义: 状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
    实现思路: 不同状态调用某些方法时效果不一样,那么新建一个状态类的接口,并在接口中写好这些方法的抽象方法。每一个不同的状态类都实现状态类接口,并各自实现这些抽象方法。 而客户在使用这些状态类时,先在定义好各个状态的成员变量,并使用一个状态类变量表示当前状态。 客户的行为通过委托该状态类变量来完成。状态改变的本质也就是状态类变量指向了不同的子类状态;从而状态类方法的行为也发生了变化。

设计原则:
1.找出程序中会变化的方面,然后将其和固定不变的方面相分离:这是设计模式的总目标
2.针对接口编程,不针对实现编程
3.多用组合,少用继承;如策略模式
4.类应该对扩展开放,对修改关闭(好的代码应该是在不修改代码的前提下可扩展的)
5.要依赖抽象,不要依赖具体类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值