设计模式
设计模式
设计模式的分类
总体来说设计模式分为三大类:
(1)创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
(2)结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
(3)行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:
Blog Catalogue:
- 1. 设计模式 观察者模式(Observer Pattern) 以微信公众服务为例
- 2. 设计模式 工厂模式(Factory Pattern) 从卖肉夹馍说起
- 3. 设计模式 单例设计模式(Singleton Pattern) 完全解析
- 4. 设计模式 策略模式(Strategy Pattern) 以角色游戏为背景
- 5. 设计模式 适配器模式(Adapter Pattern) 以手机充电器为例
- 6. 设计模式 命令模式(Command Pattern) 管理智能家电
- 7. 设计模式 装饰者模式(Decorator Pattern) 带你重回传奇世界
- 8. 设计模式 外观模式(Facade Pattern) 一键电影模式
- 9. 设计模式 模版方法模式(Template Method Pattern) 展现程序员的一天
- 10. 设计模式 状态模式(State Pattern) 以自动售货机为例
- 11. 设计模式 建造者模式(Builder Pattern) 以造汽车买汽车为例
- 12. 设计模式 原型模式(Prototype Pattern) 以获取多种形状为例
- 13. 设计模式 享元模式(Flyweight Pattern) 以随机获取多种形状为例
- 14. 设计模式 代理模式(Proxy Pattern) 以获取磁盘中的图片为例
- 15. 设计模式 桥接模式(Bridge Pattern) 以画不同颜色的圆为例
- 16. 设计模式 组合模式(Composite Pattern) 以创建和打印员工的层次结构为例
- 17. 设计模式 迭代器模式(Iterator Pattern) 以使用迭代器打印名字为例
- 18. 设计模式 中介者模式(Mediator Pattern) 以公共聊天室为例
- 19. 设计模式 备忘录模式(Memento Pattern) 以使用备忘录为例
- 20. 设计模式 解释器模式(Interpreter Pattern) 以解释一句话为例
- 21. 设计模式 责任链模式(Chain of Responsibility Pattern) 以Android Studio中打印日志为例
- 22. 设计模式 访问者模式(Visitor Pattern) 以显示计算机的组成部分为例
Pattern Analysis
1. 观察者模式
定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
-
对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。
-
专题接口:Subject.java ;
/** * 注册一个观察者 */ public void registerObserver(Observer observer); /** * 移除一个观察者 */ public void removeObserver(Observer observer); /** * 通知所有观察者 */ public void notifyObservers(); -
3D服务号的实现类:ObjectFor3D.java
-
@Override public void registerObserver(Observer observer){ observers.add(observer); } @Override public void removeObserver(Observer observer){ int index=observers.indexOf(observer); if(index>=0){observers.remove(index);}} @Override public void notifyObservers(){ for(Observer observer:observers){observer.update(msg);}} /** * 主题更新信息 */ public void setMsg(String msg){ this.msg=msg;notifyObservers(); } -
所有观察者需要实现此接口:Observer.java
public ObserverUser1(Subject subject) { subject.registerObserver(this); } @Override public void update(String msg) { Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。"); } -
// 创建服务号 objectFor3D = new ObjectFor3D(); // 创建两个订阅者 observerUser1 = new ObserverUser1(objectFor3D); observerUser2 = new ObserverUser2(objectFor3D); // 两个观察者,发送两条信息 objectFor3D.setMsg("201610121 的3D号为:127"); objectFor3D.setMsg("20161022 的3D号为:000");
2. 工厂模式
简单列一下这个模式的家族:
-
1、静态工厂模式
- 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
-
2、简单工厂模式(店里买肉夹馍)
- 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
- 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
public RoujiaMo creatRoujiaMo(String type){RoujiaMo roujiaMo=null; switch(type){ case"Suan": roujiaMo=new ZSuanRoujiaMo(); break; case"La": roujiaMo=new ZLaRoujiaMo(); break; case"Tian": roujiaMo=new ZTianRoujiaMo(); break;default:// 默认为酸肉夹馍 roujiaMo = new ZSuanRoujiaMo(); break; } return roujiaMo; } -
3、工厂方法模式(开分店)
-
定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
-
对比定义:
-
1、定义了创建对象的一个接口:
public abstract RouJiaMo sellRoujiaMo(String type); -
2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
-
-
提供创建肉夹馍店抽象方法:RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo(String type); -
具体实现抽象方法:XianRoujiaMoStore.java
-
package com.example.jingbin.designpattern.factory.gcff; import com.example.jingbin.designpattern.factory.jdgc.RoujiaMo; /** * Created by jingbin on 2016/10/24. * 西安肉夹馍店 让分店自己去卖自己口味的肉夹馍 */ public class XianRoujiaMoStore extends RoujiaMoStore { private XianSimpleRoujiaMoFactory factory; public XianRoujiaMoStore(XianSimpleRoujiaMoFactory factory) { this.factory = factory; } public RoujiaMo sellRoujiaMo(String type) { RoujiaMo roujiaMo = factory.creatRoujiaMo(type); roujiaMo.prepare(); roujiaMo.fire(); roujiaMo.pack(); return roujiaMo; } // @Override // public RoujiaMo creatRoujiaMo(String type) { // // RoujiaMo roujiaMo = null; // switch (type) { // case "suan": // roujiaMo = new XianSuanRoujiMo(); // break; // case "tian": // roujiaMo = new XianKuRoujiMo(); // break; // case "la": // roujiaMo = new XianlaRoujiMo(); // break; // default:// 默认为 西安 酸肉夹馍 // roujiaMo = new XianSuanRoujiMo(); // break; // } // return roujiaMo; // } } -
分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java
package com.example.jingbin.designpattern.factory.gcff;
import com.example.jingbin.designpattern.factory.jdgc.RoujiaMo;
/**
* Created by jingbin on 2016/10/23.
* 西安 简单工厂模式:
* 用来西安店生产自己店里的肉夹馍
*/
public class XianSimpleRoujiaMoFactory {
public RoujiaMo creatRoujiaMo(String type) {
RoujiaMo roujiaMo = null;
switch (type) {
case "Suan":
roujiaMo = new XianSuanRoujiMo();
break;
case "La":
roujiaMo = new XianKuRoujiMo();
break;
case "Tian":
roujiaMo = new XianlaRoujiMo();
break;
default:// 默认为酸肉夹馍
roujiaMo = new XianSuanRoujiMo();
break;
}
return roujiaMo;
}
}
-
4、抽象工厂模式(使用官方提供的原料)
-
定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
-
对比定义:
-
1、提供一个接口:
public interface RouJiaMoYLFactroy -
2、用于创建相关的或依赖对象的家族
public Meat createMeat(); public YuanLiao createYuanliao(); -
我们接口用于创建一系列的原材料。
-
-
创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
-
各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
-
准备时,使用官方的原料:RoujiaMo.java
/** * 准备工作 */ public void prepare(RoujiaMoYLFactory roujiaMoYLFactory) { Meet meet = roujiaMoYLFactory.creatMeet(); YuanLiao yuanLiao = roujiaMoYLFactory.creatYuanLiao(); Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao); } -
3. 单例设计模式
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
- 定义:只需要三步就可以保证对象的唯一性
- (1) 不允许其他程序用new对象
- (2) 在该类中创建对象
- (3) 对外提供一个可以让其他程序获取该对象的方法
- 对比定义:
- (1) 私有化该类的构造函数
- (2) 通过new在本类中创建一个本类对象
- (3) 定义一个公有的方法,将在该类中所创建的对象返回
- 饿汉式[可用]:SingletonEHan.java
- 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java
private SingletonLanHan() {}
private static SingletonLanHan singletonLanHanFour;
public static SingletonLanHan getSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = new SingletonLanHan();
}
}
}
return singletonLanHanFour;
}
复制
- 内部类[推荐用]:SingletonIn.java
- 枚举[推荐用]:SingletonEnum.java
4. 策略模式
策略模式:定义了算法族,分别封装起来,让它们之间可相互替换,此模式让算法的变化独立于使用算法的客户。
- 以创建游戏角色为例子:
- 总结:
- 1、封装变化(把可能变化的代码封装起来)
- 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
- 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
- 最后测试:创建角色:
RoleA roleA = new RoleA("---A");
roleA.setiDisplayBehavior(new DisplayYZ())
.setiAttackBehavior(new AttackXL())
.setiDefendBehavior(new DefendTMS())
.setiRunBehavior(new RunJCTQ());
roleA.display();// 样子
roleA.attack();// 攻击
roleA.run();// 逃跑
roleA.defend();// 防御
复制
5. 适配器模式
定义:将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作。这个定义还好,说适配器的功能就是把一个接口转成另一个接口。
- 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)
- 一部手机: Mobile.java
- 手机依赖一个提供5V电压的接口: V5Power.java
- 我们拥有的是220V家用交流电: V220Power.java
- 适配器,完成220V转5V的作用:V5PowerAdapter.java
- 最后测试:给手机冲个电: Mobile mobile = new Mobile(); V5Power v5Power = new V5PowerAdapter(new V200Power()); mobile.inputPower(v5Power);
6. 命令模式
定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(简化: 将请求封装成对象,将动作请求者和动作执行者解耦。)
- 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
- 1、家电的API:Door.java
- 2、把命令封装成类:
- 统一的命令接口:Command.java
- 家电实现该接口:DoorOpenCommand.java
- 3、遥控器:ControlPanel.java
- 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommand quickCloseCommand = new QuickCommand(new Command[]{new LightOffCommand(light), new ComputerOffCommand(computer), new DoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
复制
- 5、遥控器面板执行:CommandActivity.java
controlPanel.setCommands(0, new DoorOpenCommand(door));// 开门
controlPanel.keyPressed(0);
复制
7. 装饰者模式
装饰者模式:若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。
-
先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。
-
需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:
-
1、装备的超类:IEquip.java
-
2、各个装备的实现类:
- eg:武器的实现类: ArmEquip.java
-
3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java
-
4、装饰品的实现类:
- eg:蓝宝石的实现类(可累加): BlueGemDecorator.java
-
5、最后测试:计算攻击力和查看描述:
Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: "); IEquip iEquip = new RedGemDecotator(new RedGemDecotator(new BlueGemDecotator(new ShoeEquip()))); Log.e("---", "攻击力:" + iEquip.caculateAttack()); Log.e("---", "描述语:" + iEquip.description());
8. 外观模式
定义:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。其实就是为了方便客户的使用,把一群操作,封装成一个方法。
-
需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。
-
每个设备类的开关等操作:
-
eg: 爆米花机:PopcornPopper.java
-
/** * 一键观影 */ public void watchMovie() { computer.on(); light.down(); popcornPopper.on(); popcornPopper.makePopcorn(); projector.on(); projector.open(); player.on(); player.make3DListener(); } -
最后测试:一键观影:
new HomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();
9. 模板方法模式
定义:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。
-
需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况
-
模板方法模式中的三类角色
-
1、具体方法(Concrete Method)
-
2、抽象方法(Abstract Method)
-
3、钩子方法(Hook Method)
-
工人的超类:Worker.java
// 具体方法 public final void workOneDay() { Log.e("workOneDay", "-----------------work start----------------"); enterCompany(); work(); exitCompany(); Log.e("workOneDay", "-----------------work end----------------"); } // 工作 抽象方法 public abstract void work(); // 钩子方法 public boolean isNeedPrintDate() { return false; } private void exitCompany() { if (isNeedPrintDate()) { Log.e("exitCompany", "---" + new Date().toLocaleString() + "--->"); } Log.e("exitCompany", name + "---离开公司"); } -
程序员实现类(可得知时间):ITWorker.java /** * 重写父类的此方法,使可以查看离开公司时间 */ @Override public boolean isNeedPrintDate()
-
最后测试:
-
查看所有人员的工作情况:
QAWorker qaWorker = new QAWorker("测试人员"); qaWorker(); HRWorker hrWorker = new HRWorker("莉莉姐"); hrWorker.workOneDay(); ... -
查看程序猿离开公司的时间:
ITWorker itWorker = new ITWorker("jingbin"); itWorker.workOneDay();
-
10. 状态模式
定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
-
定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。
-
需求:已自动售货机为例(有已投币、未投币等状态和投币、投币等方法)
-
最初实现待改进的售货机:VendingMachine.java
-
改进后的售货机(更具有延展性):VendingMachineBetter.java
// 放钱 public void insertMoney() { currentState.insertMoney(); } // 退钱 public void backMoney() { currentState.backMoney(); } // 转动曲柄 public void turnCrank() { currentState.turnCrank(); if (currentState == soldState || currentState == winnerState) { currentState.dispense(); //两种情况会出货 } } // 出商品 public void dispense() { Log.e("VendingMachineBetter", "---发出一件商品"); if (count > 0) { count--; } } // 设置对应状态 public void setState(State state) { this.currentState = state; } -
状态的接口:State.java
-
对应状态的接口实现类:
- eg: 中奖状态:WinnerState.java
- eg: 售卖状态:SoldState.java
-
改进后的售货机测试:
// 初始化售货机,且里面有3个商品 VendingMachineBetter machineBetter = new VendingMachineBetter(3); machineBetter.insertMoney(); machineBetter.turnCrank();
11. 建造者模式
建造模式是对象的创建模式。建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
-
需求:用户去汽车店购买汽车。
-
分析:汽车店根据每个用户的需求提取对应汽车
-
建造者超类:Builder
public abstract class Builder { public abstract void setPart(String name, String type); public abstract Product getProduct(); } -
建造者对应实现类:ConcreteBuilder
- public class ConcreteBuilder extends Builder { private Product product = new Product(); @Override public void setPart(String name, String type) { product.setName(name); product.setType(type); } @Override public Product getProduct() { return product; } } -店长Director取汽车:
// 店长 Director director = new Director(); // 得到宝马汽车,内部实现提取宝马汽车的详情操作 Product product = director.getBProduct(); // 展示汽车信息 product.showProduct();
12. 原型模式
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
以获取多种形状为例,共分四步:
-
1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)
-
public abstract class Shape implements Cloneable { private String id; protected String type; public abstract void draw(); public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public Object clone() { Object object = null; try { object = super.clone(); } catch (CloneNotSupportedException e) { Log.e("--", e.getMessage()); } return object; } } -
2、创建扩展了上面抽象类的实体类。Circle、Rectangle、Square
public class Circle extends Shape { public Circle() { type = "Circle"; } @Override public void draw() { Log.e("---", "Inside Circle::draw() method."); } } -
3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache
-
public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape shapeCache = shapeMap.get(shapeId); return (Shape) shapeCache.clone(); } // 对每种形状都运行数据库查询,并创建该形状 shapeMap.put(shapeKey, shape); // 例如,我们要添加三种形状 public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(), circle); Rectangle rectangle = new Rectangle(); rectangle.setId("2"); shapeMap.put(rectangle.getId(), rectangle); Square square = new Square(); square.setId("3"); shapeMap.put(square.getId(), square); } } -
4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。 ShapeCache.loadCache(); Shape shapeCache1 = ShapeCache.getShape("1"); Shape shapeCache2 = ShapeCache.getShape("2"); Shape shapeCache3 = ShapeCache.getShape("3");
13. 享元模式
主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。
- 主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
以随机获取多种形状为例,共分四步:
-
1、创建一个接口。
public interface Shape { void draw(); } -
2、创建实现接口的实体类。
-
public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color) { this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { Log.e("---", "Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius); } } -
3、创建一个工厂,生成基于给定信息的实体类的对象。
-
- public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap<String, Shape>(); public static Shape getShape(String color) { Shape shape = circleMap.get(color); if (shape == null) { shape = new Circle(color); circleMap.put(color, shape); Log.e("getShape", "Creating circle of color : " + color); } return shape; } } - -
4、使用该工厂,通过传递颜色信息来获取实体类的对象。
for (int i = 0; i < 20; i++) { Circle circle = (Circle) ShapeFactory.getShape(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); }
14. 代理模式
一个类代表另一个类的功能。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。可以理解为内存中没有这个对象就创建,有就直接返回这个对象。
- 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
以获取磁盘中的图片为例,总共分三步:
-
1、创建一个接口。
public interface Image { void display(); } -
2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。
public class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadFromDisk(fileName); } private void loadFromDisk(String fileName) { Log.e("RealImage", "loading " + fileName); } @Override public void display() { Log.e("RealImage", "Displaying " + fileName); } } public class ProxyImage implements Image { private String fileName; private RealImage realImage; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (realImage == null) { realImage = new RealImage(fileName); } realImage.display(); } } -
3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
Image image = new ProxyImage("test_10mb.png"); // 第一次是new的,图像从磁盘加载 image.display(); // 第二次取缓存,图像不需要从磁盘加载 image.display();
15. 桥接模式
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
- 主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
以画不同颜色的圆为例,实现共分五步:
-
1、创建桥接实现接口。
public interface DrawAPI { void drawCircle(int radius, int x, int y); } -
2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircle、GreenCircle
public class RedCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { Log.e("---", "Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", " + y + "]"); } } -
3、使用 DrawAPI 接口创建抽象类 Shape。
- public abstract class Shape { protected DrawAPI drawAPI; protected Shape(DrawAPI drawAPI) { this.drawAPI = drawAPI; } public abstract void draw(); } -4、创建实现了 Shape 接口的实体类。
public class Circle extends Shape { private int x, y, radius; protected Circle(int x, int y, int radius, DrawAPI drawAPI) { super(drawAPI); this.x = x; this.y = y; this.radius = radius; } @Override public void draw() { drawAPI.drawCircle(radius, x, y); } } -
5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。
// 画红圆 Circle circle = new Circle(10, 10, 100, new RedCircle());s circle.draw(); // 画绿圆 Circle circle2 = new Circle(20, 20, 100, new GreenCircle()); circle2.draw();
16. 组合模式
又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
- 主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
以创建和打印员工的层次结构为例,最小单元示例:
-
1、创建 Employee 类,该类带有 Employee 对象的列表。
public class Employee { private String name; // 部门 private String dept; // 工资 private int salary; // 员工 list private List<Employee> subordinates; public Employee(String name, String dept, int salary) { this.name = name; this.dept = dept; this.salary = salary; this.subordinates = new ArrayList<Employee>(); } public void add(Employee e) { subordinates.add(e); } public void remove(Employee e) { subordinates.remove(e); } public List<Employee> getSubordinates() { return subordinates; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", dept='" + dept + '\'' + ", salary=" + salary + ", subordinates=" + subordinates + '}'; } } -
2.使用 Employee 类来创建和打印员工的层次结构。
final Employee ceo = new Employee("John", "CEO", 30000); Employee headSales = new Employee("Robert", "Head sales", 20000); Employee headMarketing = new Employee("Michel", "Head Marketing", 20000); Employee clerk1 = new Employee("Laura", "Marketing", 10000); Employee clerk2 = new Employee("Bob", "Marketing", 10000); Employee salesExecutive1 = new Employee("Richard", "Sales", 10000); Employee salesExecutive2 = new Employee("Rob", "Sales", 10000); ceo.add(headSales); ceo.add(headMarketing); headSales.add(salesExecutive1); headSales.add(salesExecutive2); headMarketing.add(clerk1); headMarketing.add(clerk2); Log.e("---",ceo.toString()); // 打印 /* * Employee{name='John', dept='CEO', salary=30000, // * subordinates=[Employee{name='Robert', dept='Head sales', salary=20000, // * subordinates=[ * Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]}, // * Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]}, // * Employee{name='Michel', dept='Head Marketing', salary=20000, // * subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]}, // * Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]} */
17. 迭代器模式
Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式属于行为型模式。
- 主要解决:不同的方式来遍历整个整合对象。
以使用迭代器打印名字为例,总共分三步:
-
1、创建接口: public interface Iterator { public boolean hasNext(); public Object next(); } public interface Container
-
2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。
public class NameRepository implements Container { private String names[] = {"John", "jingbin", "youlookwhat", "lookthis"}; @Override public Iterator getIterator() { return new NameIterator(); } private class NameIterator implements Iterator { int index; @Override public boolean hasNext() { if (index < names.length) { return true; } return false; } @Override public Object next() { if (hasNext()) { return names[index++]; } return null; } } } -
3、使用 NameRepository 来获取迭代器,并打印名字。
NameRepository nameRepository = new NameRepository(); for (Iterator iterator = nameRepository.getIterator(); iterator.hasNext(); ) { String name = (String) iterator.next(); Log.e("---", name); /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */ }
18. 中介者模式
用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
- 主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
以公共聊天室为例,最小单元示例步骤:
-
1、创建中介类。
public class CharRoom { public static void showMessage(User user, String message) { Log.e("---", new Date().toString() + " [" + user.getName() + "] : " + message); } } -
2、创建 user 类。
public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void sendMessage(String message) { // 使用中介类 CharRoom.showMessage(this, message); } } -
3、使用 User 对象来显示他们之间的通信。
User jingbin = new User("jingbin"); jingbin.sendMessage("Hi~ youlookwhat!"); //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat! // User jingbin = new User("youlookwhat"); jingbin.sendMessage("Hi~ jingbin!"); //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
19. 备忘录模式
保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。
- 主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
以使用备忘录为例,最小单元步骤:
-
1、创建 备忘录 Memento 类。
public class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } -
2、创建 Originator 类。
public class Originator { private String state; public String getState() { return state; } public void setState(String state) { this.state = state; } public Memento setSateToMemento() { return new Memento(state); } public String getStateFromMemento(Memento memento) { return memento.getState(); } } -
3、创建 CareTaker 类。
public class CareTaker { private List<Memento> mementoList = new ArrayList<Memento>(); public void add(Memento memento) { mementoList.add(memento); } public Memento get(int index) { return mementoList.get(index); } } -
4、使用 CareTaker 和 Originator 对象
// 管理者 CareTaker careTaker = new CareTaker(); Originator originator = new Originator(); originator.setState("State #1"); originator.setState("State #2"); // 保存状态 careTaker.add(originator.setSateToMemento()); originator.setState("State #3"); // 保存状态 careTaker.add(originator.setSateToMemento()); originator.setState("State #4"); Log.e("---", "Current State: " + originator.getState()); // 得到保存的状态 String fromMemento1 = originator.getStateFromMemento(careTaker.get(0)); Log.e("---", "First Saved State: " + fromMemento1); String fromMemento2 = originator.getStateFromMemento(careTaker.get(1)); Log.e("---", "Second Saved State: " + fromMemento2); /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */
20. 解释器模式
提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
- 主要解决:对于一些固定文法构建一个解释句子的解释器。
以解释一句话为例,最小单元步骤:
-
1、创建一个表达式接口 Expression。
public interface Expression { public boolean interpreter(String content); } -
2、创建实现了上述接口的实体类。
TerminalExpression、OrExpression、AndExpression。 public class TerminalExpression implements Expression { private String data; public TerminalExpression(String data) { this.data = data; } @Override public boolean interpreter(String content) { // 是包含判断 return content.contains(data); } } public class OrExpression implements Expression { private Expression expression1; private Expression expression2; public OrExpression(Expression expression1, Expression expression2) { this.expression1 = expression1; this.expression2 = expression2; } @Override public boolean interpreter(String content) { return expression1.interpreter(content) || expression2.interpreter(content); } } public class AndExpression implements Expression { private Expression expression1; private Expression expression2; public AndExpression(Expression expression1, Expression expression2) { this.expression1 = expression1; this.expression2 = expression2; } @Override public boolean interpreter(String content) { return expression1.interpreter(content) && expression2.interpreter(content); } } -
3、使用 Expression 类来创建规则,并解析它们。
/** * 规则:jingbin 和 youlookwhat 是男性 */ public static Expression getMaleExpression() { TerminalExpression jingbin = new TerminalExpression("jingbin"); TerminalExpression youlookwhat = new TerminalExpression("youlookwhat"); return new OrExpression(jingbin, youlookwhat); } /** * 规则:Julie 是一个已婚的女性 */ public static Expression getMarriedWomanExpression() { TerminalExpression julie = new TerminalExpression("Julie"); TerminalExpression married = new TerminalExpression("Married"); return new AndExpression(julie, married); } Expression maleExpression = getMaleExpression(); // jingbin is male: true Log.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin")); Expression womanExpression = getMarriedWomanExpression(); // Julie is married woman: true Log.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));
21. 责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
- 主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
以Android Studio中打印日志为例,最小单元步骤:
-
1、创建抽象的记录器类 AbstractLogger。
public abstract class AbstractLogger { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; protected int level; // 责任链中的下一个元素 protected AbstractLogger nextLogger; public void setNextLogger(AbstractLogger nextLogger) { this.nextLogger = nextLogger; } public void logMessage(int level, String message) { if (this.level <= level) { write(message); } // 递归效果,不断调用下一级 logMessage if (nextLogger != null) { nextLogger.logMessage(level, message); } } protected abstract void write(String message); } -
2、创建扩展了该记录器类的实体类。
public class ConsoleLogger extends AbstractLogger { public ConsoleLogger(int level) { this.level = level; } @Override protected void write(String message) { Log.e("---", "Standard Console::Logger " + message); } } public class FileLogger extends AbstractLogger { public FileLogger(int level) { this.level = level; } @Override protected void write(String message) { Log.e("---", "File::Logger " + message); } } public class ErrorLogger extends AbstractLogger { public ErrorLogger(int level) { this.level = level; } @Override protected void write(String message) { Log.e("---", "Error Console::Logger " + message); } } -
3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
public static AbstractLogger getChainOfLoggers() { ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR); FileLogger fileLogger = new FileLogger(AbstractLogger.DEBUG); ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO); errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); return errorLogger; } AbstractLogger logger = getChainOfLoggers(); // ---: Standard Console::Logger this is an information. logger.logMessage(AbstractLogger.INFO, "this is an information."); // ---: File::Logger this is a debug level information. // ---: Standard Console::Logger this is a debug level information. logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information."); // ---: Error Console::Logger this is a error level information. // ---: File::Logger this is a error level information. // ---: Standard Console::Logger this is a error level information. logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");
22. 访问者模式
在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
- 主要解决:稳定的数据结构和易变的操作耦合问题。
以显示计算机的组成部分为例,主要分五步实现:
-
1、定义一个表示元素的接口。
public interface ComputerPart { public void accept(ComputerPartVisitor computerPartVisitor); } -
2、创建扩展了上述类的实体类。Keyboard、Monitor、Mouse、Computer
public class Computer implements ComputerPart { private ComputerPart[] parts; public Computer() { this.parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()}; } @Override public void accept(ComputerPartVisitor computerPartVisitor) { for (ComputerPart part : parts) { part.accept(computerPartVisitor); } computerPartVisitor.visit(this); } } public class Mouse implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } -
3、定义一个表示访问者的接口。
public interface ComputerPartVisitor { public void visit(Computer computer); public void visit(Mouse mouse); public void visit(Keyboard keyboard); public void visit(Monitor monitor); } -
4、创建实现了上述类的实体访问者。
public class ComputerPartDisplayVisitor implements ComputerPartVisitor { @Override public void visit(Computer computer) { Log.e("---", "Displaying Computer."); } @Override public void visit(Mouse mouse) { Log.e("---", "Displaying Mouse."); } @Override public void visit(Keyboard keyboard) { Log.e("---", "Displaying Keyboard."); } @Override public void visit(Monitor monitor) { Log.e("---", "Displaying Monitor."); } } -
5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
ComputerPart computer = new Computer(); computer.accept(new ComputerPartDisplayVisitor()); /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */
设计模式的六大原则
开闭原则(总原则)
【对扩展开放,对修改关闭】
在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码。
可以通过“抽象约束、封装变化”来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。
抽象的设计方式灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。同时软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需根据需求重新派生一个实现类来扩展功能即可。
里氏替换原则
【任何父类可以出现的地方,子类一定可以出现】。
该原则是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用。
实现开闭原则的关键步骤就是抽象化,而父类与子类的继承关系就是抽象化的具体实现。因此,里氏代换原则是对开闭原则的补充。
该原则简单来说,就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。其具体体现为:
子类必须实现父类的抽象方法,但不能重写父类的非抽象(已实现的)方法。
子类中可以增加自己特有的方法。
当子类覆盖或者实现父类的方法时,方法的前置条件(方法形参)要比父类输入参数更加宽松,否则会调用到父类的方法。
当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格,否则会调用到父类的方法。
如果程序违背了里氏替换原则,就需要取消原来的继承关系,重新设计它们之间的关系。
依赖倒置原则
【程序要依赖于抽象接口,不要依赖于具体实现】。
该原则其定义中包含了三层含义:
1>高层模块不应该依赖低层模块,两者都应该依赖其抽象。
2>抽象不应该依赖细节。
3>细节应该依赖抽象。
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
该原则的核心思想是:要面向接口(接口或者抽象类)编程,不要面向实现(具体的实现类)编程。在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多(这里的抽象指的是接口或者抽象类,而细节是指具体的实现类)。
依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,在实际开发中,该原则的具体体现为:
每个类尽量提供接口或抽象类,或者两者都具备。
变量的声明类型尽量是接口或者是抽象类。
任何类都不应该从具体类派生。
使用继承时尽量遵循里氏替换原则。
单一职责原则
【一个类应该有且仅有一个引起它变化的原因,否则类就应该被拆分】。
如果一个类承担了太多的职责,至少存在以下两个缺点:
1) 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力。
2)当客户端需要使用该对象的某一个职责时,不得不同时实现其他职责,从而造成冗余代码或代码的浪费。
单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点:
降低类的复杂度。
提高类的可读性。
提高系统的可维护性。
变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。
如果一个类承担的责任过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
软件设计要做的很多内容,就是发现职责并把那些职责相互分离。至于判断的标准,就是:如果能想到多余一个的动机去改变一个类,那么这个类就具有多于一个的职责。
单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。
接口隔离原则
【一个类对另一个类的依赖应该建立在最小的接口上】
接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的,区别如下:
单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。
单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。
在具体应用接口隔离原则时,需要从以下几个方面考虑:
接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准也不同。
提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
隔离:建立单一接口,不要建立臃肿庞大的接口;即接口要尽量细化,同时接口中的方法要尽量少。
接口隔离原则与单一职责原则的不同:接口隔离原则与单一职责的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。
迪米特法则
【只与你的直接朋友(前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等)交谈,不跟“陌生人”说话】。
其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。该原则的目的是降低类之间的耦合度,提高模块的相对独立性。
从迪米特法则的定义可知,它强调以下两点:
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。
所以,在运用迪米特法则时要注意以下 6 点:
在类的划分上,应该创建弱耦合的类。
在类的结构设计上,尽量降低类成员的访问权限。
在类的设计上,优先考虑将一个类设置成不变类。
在对其他类的引用上,将引用其他对象的次数降到最低。
不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。
谨慎使用序列化功能。
合成复用原则
【尽量先使用组合、聚合等关联关系来实现,其次才考虑使用继承关系来实现】。
如果要使用继承关系,则必须严格遵循里氏替换原则。
采用组合或聚合的方式复用类时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
维持了类的封装性。
新旧类之间的耦合度低。
复用的灵活性高。
设计模式的适用场景
模式 适用场景
单例模式 1)只要求生成一个全局对象
2)需要频繁实例化,而创建的对象又频繁被销毁
工厂方法模式 父工厂类中只有创建产品的抽象接口,将产品对象的实际创建工作推迟到具体子工厂类当中
抽象工厂模式 系统中有多个产品类,但每次只使用其中的某一类产品
建造者模式 对象可以分模块初始化
原型模式 1)不同对象之间相似度高
2)创建对象比较麻烦,但复制比较简单
适配器模式 不同模块之间接口不一致
桥接模式 不同类都有多个变化的维度,这些维度可以组合成不同的结果
组合模式 示一个对象整体与部分的层次结构
装饰器模式 不影响原有模块功能,需要动态地添加、撤销一些附属功能
外观模式 隐藏子系统的复杂操作,对外提供简单的接口
享元模式 系统中存在大量相同或相似的对象,只保存一个就行
代理模式 控制访问权限
模板模式 子类执行固定步骤下的不同具体步骤
策略模式 不同算法互相替代使用
状态模式 态在很大程度上决定了系统的运行
观察者模式 实现群发、群消息提醒等一对多功能
备忘录模式 需要保存与恢复数据的场景
中介者模式 不同对象之间关系复杂,需要调整
迭代器模式 为遍历某种结构提供统一接口
解释器模式 语言的文法较为简单,格式固定
命令模式 请求调用者与请求接收者解耦
责任链模式 有多个对象可以处理一个请求
访问者模式 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构
区别
1、状态模式与策略模式的区别
状态模式关注对象所处的状态,封装了依赖于状态的行为;
策略模式关注对象如何执行特定的任务,它封装的是算法。
2、策略模式与模板方法模式
在模板方法中,算法是在编译时通过继承选择的;
使用策略模式,算法在运行时通过组合选择。
3、代理模式与装饰器模式
代理模式控制对象访问权限;装饰模式用于向对象添加职责。
装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
相同点:都是为被代理(被装饰)的类扩充新的功能。
不同点:代理模式具有控制被代理类的访问等性质,而装饰模式紧紧是单纯的扩充被装饰的类。所以区别仅仅在是否对被代理/被装饰的类进行了控制而已。
4、工厂模式与创建者模式
创建者模式可以将零件对象组装成整体;
而工厂模式直接给出完整的对象。
建造者模式最主要的功能是基本方法的调用顺序安排,这些基本方法已经实现了,顺序不同产生的对象也不同;工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。
5、访问者模式与迭代器模式
访问者模式一般遍历复杂结构,如树结构或组合结构等,结构中每个结点可以同构也可以异构,前提是只要提供一个预定的统一访问接口即可;
迭代器模式用于遍历元素类型一致的集合(多是线性结构,当然也可以是非线性结构),不用为每个元素定义统一的访问接口。
6、适配器模式与外观模式
适配器模式一般只包装一个对象,目标是为了改变接口来适应外部系统,但要完成的功能没变;
外观模式 一般是将一个子系统进行包装,目的是简化接口。
7、装饰器模式与适配器模式
装饰器模式是为了给现有对象增加功能,一般接口不变或接口增加;
适配器模式是为了改变其接口,功能保持不变。
8、工厂模式与原型模式
工厂模式是重新创建一个对象;
原型模式是从已有的实例直接拷贝生成一个实例,从而省去了初始化的过程。
9、备忘录模式与命令模式
两种模式都可以提供回到先前某点的功能,但前者是针对对象状态,后者针对对象行为。
10、抽象工厂和工厂方法模式
工厂方法:创建某个具体产品。抽象工厂:创建某个产品族中的系列产品。

浙公网安备 33010602011771号