设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
设计模式分为三种类型,共23种:
- 创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
- 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
- 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式、访问者模式。
参照Hongyang、菜鸟教程等处文章所写。如有错误欢迎指正,如有侵权,请联系我删除。
定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。
专题接口:Subject.java ;
/** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver); /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver); /** * 通知所有观察者 */publicvoidnotifyObservers();
3D服务号的实现类:ObjectFor3D.java
@OverridepublicvoidregisterObserver(Observerobserver){observers.add(observer)} @OverridepublicvoidremoveObserver(Observerobserver){intindex = observers.indexOf(observer); if (index >= 0){observers.remove(index)} } @OverridepublicvoidnotifyObservers(){for (Observerobserver : observers){observer.update(msg)} } /** * 主题更新信息 */publicvoidsetMsg(Stringmsg){this.msg = msg; notifyObservers()}
所有观察者需要实现此接口:Observer.java
publicObserverUser1(Subjectsubject){subject.registerObserver(this)} @Overridepublicvoidupdate(Stringmsg){Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。")}
// 创建服务号objectFor3D = newObjectFor3D(); // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D); observerUser2 = newObserverUser2(objectFor3D); // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127"); objectFor3D.setMsg("20161022 的3D号为:000");
简单列一下这个模式的家族:
1、静态工厂模式
- 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
2、简单工厂模式(店里买肉夹馍)
- 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
- 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
publicRoujiaMocreatRoujiaMo(Stringtype){RoujiaMoroujiaMo = null; switch (type){case"Suan": roujiaMo = newZSuanRoujiaMo(); break; case"La": roujiaMo = newZLaRoujiaMo(); break; case"Tian": roujiaMo = newZTianRoujiaMo(); break; default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo(); break} returnroujiaMo}
3、工厂方法模式(开分店)
- 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
- 对比定义:
- 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
- 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
提供创建肉夹馍店抽象方法:RoujiaMoStore.java
publicabstractRoujiaMosellRoujiaMo(Stringtype);
具体实现抽象方法:XianRoujiaMoStore.java
分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java
4、抽象工厂模式(使用官方提供的原料)
- 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
- 对比定义:
- 1、提供一个接口:public interface RouJiaMoYLFactroy
- 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
- 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
- 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
- 准备时,使用官方的原料:RoujiaMo.java
/** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory){Meetmeet = roujiaMoYLFactory.creatMeet(); YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao(); Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao)}
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
定义:只需要三步就可以保证对象的唯一性
- (1) 不允许其他程序用new对象
- (2) 在该类中创建对象
- (3) 对外提供一个可以让其他程序获取该对象的方法
对比定义:
- (1) 私有化该类的构造函数
- (2) 通过new在本类中创建一个本类对象
- (3) 定义一个公有的方法,将在该类中所创建的对象返回
饿汉式[可用]:SingletonEHan.java
含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java
privateSingletonLanHan(){} privatestaticSingletonLanHansingletonLanHanFour; publicstaticSingletonLanHangetSingletonLanHanFour(){if (singletonLanHanFour == null){synchronized (SingletonLanHan.class){if (singletonLanHanFour == null){singletonLanHanFour = newSingletonLanHan()} } } returnsingletonLanHanFour} - 内部类[推荐用]:SingletonIn.java
- 枚举[推荐用]:SingletonEnum.java
策略模式:定义了算法族,分别封装起来,让它们之间可相互替换,此模式让算法的变化独立于使用算法的客户。
- 以创建游戏角色为例子:
- 总结:
- 1、封装变化(把可能变化的代码封装起来)
- 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
- 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
- 最后测试:创建角色:
RoleAroleA = newRoleA("---A"); roleA.setiDisplayBehavior(newDisplayYZ()) .setiAttackBehavior(newAttackXL()) .setiDefendBehavior(newDefendTMS()) .setiRunBehavior(newRunJCTQ()); roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御定义:将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作。这个定义还好,说适配器的功能就是把一个接口转成另一个接口。
以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)
一部手机: Mobile.java
手机依赖一个提供5V电压的接口: V5Power.java
我们拥有的是220V家用交流电: V220Power.java
适配器,完成220V转5V的作用:V5PowerAdapter.java
最后测试:给手机冲个电:
Mobilemobile = newMobile(); V5Powerv5Power = newV5PowerAdapter(newV200Power()); mobile.inputPower(v5Power);
定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(简化: 将请求封装成对象,将动作请求者和动作执行者解耦。)
- 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
- 1、家电的API:Door.java
- 2、把命令封装成类:
- 统一的命令接口:Command.java
- 家电实现该接口:DoorOpenCommand.java
- 3、遥控器:ControlPanel.java
- 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)}); controlPanel.setCommands(6, quickOpenCommand); controlPanel.keyPressed(6);- 5、遥控器面板执行:CommandActivity.java
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);装饰者模式:若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。
先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。
需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:
1、装备的超类:IEquip.java
2、各个装备的实现类:
- eg:武器的实现类: ArmEquip.java
3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java
4、装饰品的实现类:
- eg:蓝宝石的实现类(可累加): BlueGemDecorator.java
5、最后测试:计算攻击力和查看描述:
Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: "); IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip()))); Log.e("---", "攻击力:" + iEquip.caculateAttack()); Log.e("---", "描述语:" + iEquip.description());
定义:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。其实就是为了方便客户的使用,把一群操作,封装成一个方法。
需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。
每个设备类的开关等操作:
eg: 爆米花机:PopcornPopper.java
/** * 一键观影 */publicvoidwatchMovie(){computer.on(); light.down(); popcornPopper.on(); popcornPopper.makePopcorn(); projector.on(); projector.open(); player.on(); player.make3DListener()}
最后测试:一键观影:
newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();
定义:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。
需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况
模板方法模式中的三类角色
1、具体方法(Concrete Method)
2、抽象方法(Abstract Method)
3、钩子方法(Hook Method)
工人的超类:Worker.java
// 具体方法publicfinalvoidworkOneDay(){Log.e("workOneDay", "-----------------work start----------------"); enterCompany(); work(); exitCompany(); Log.e("workOneDay", "-----------------work end----------------")} // 工作 抽象方法publicabstractvoidwork(); // 钩子方法publicbooleanisNeedPrintDate(){returnfalse} privatevoidexitCompany(){if (isNeedPrintDate()){Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->")} Log.e("exitCompany", name + "---离开公司")}
程序员实现类(可得知时间):ITWorker.java
/** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate(){returntrue}
最后测试:
查看所有人员的工作情况:
QAWorkerqaWorker = newQAWorker("测试人员"); qaWorker(); HRWorkerhrWorker = newHRWorker("莉莉姐"); hrWorker.workOneDay(); ...
查看程序猿离开公司的时间:
ITWorkeritWorker = newITWorker("jingbin"); itWorker.workOneDay();
定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。
需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)
最初实现待改进的售货机:VendingMachine.java
改进后的售货机(更具有延展性):VendingMachineBetter.java
// 放钱publicvoidinsertMoney(){currentState.insertMoney()} // 退钱publicvoidbackMoney(){currentState.backMoney()} // 转动曲柄publicvoidturnCrank(){currentState.turnCrank(); if (currentState == soldState || currentState == winnerState){currentState.dispense();//两种情况会出货 } } // 出商品publicvoiddispense(){Log.e("VendingMachineBetter", "---发出一件商品"); if (count > 0){count--} } // 设置对应状态publicvoidsetState(Statestate){this.currentState = state}
状态的接口:State.java
对应状态的接口实现类:
- eg: 中奖状态:WinnerState.java
- eg: 售卖状态:SoldState.java
改进后的售货机测试:
// 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3); machineBetter.insertMoney(); machineBetter.turnCrank();
建造模式是对象的创建模式。建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
需求:用户去汽车店购买汽车。
分析:汽车店根据每个用户的需求提取对应汽车
建造者超类:Builder
publicabstractclassBuilder{publicabstractvoidsetPart(Stringname, Stringtype); publicabstractProductgetProduct()}
建造者对应实现类:ConcreteBuilder
publicclassConcreteBuilderextendsBuilder{privateProductproduct = newProduct(); @OverridepublicvoidsetPart(Stringname, Stringtype){product.setName(name); product.setType(type)} @OverridepublicProductgetProduct(){returnproduct} }
店长Director取汽车:
// 店长Directordirector = newDirector(); // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct(); // 展示汽车信息product.showProduct();
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
以获取多种形状为例,共分四步:
1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)
publicabstractclassShapeimplementsCloneable{privateStringid; protectedStringtype; publicabstractvoiddraw(); publicStringgetId(){returnid} publicvoidsetId(Stringid){this.id = id} @OverridepublicObjectclone(){Objectobject = null; try{object = super.clone()} catch (CloneNotSupportedExceptione){Log.e("--", e.getMessage())} returnobject} }
2、创建扩展了上面抽象类的实体类。Circle、Rectangle、Square
publicclassCircleextendsShape{publicCircle(){type = "Circle"} @Overridepublicvoiddraw(){Log.e("---", "Inside Circle::draw() method.")} }
3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache
publicclassShapeCache{privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>(); publicstaticShapegetShape(StringshapeId){ShapeshapeCache = shapeMap.get(shapeId); return (Shape) shapeCache.clone()} // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache(){Circlecircle = newCircle(); circle.setId("1"); shapeMap.put(circle.getId(), circle); Rectanglerectangle = newRectangle(); rectangle.setId("2"); shapeMap.put(rectangle.getId(), rectangle); Squaresquare = newSquare(); square.setId("3"); shapeMap.put(square.getId(), square)} }
4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache(); ShapeshapeCache1 = ShapeCache.getShape("1"); ShapeshapeCache2 = ShapeCache.getShape("2"); ShapeshapeCache3 = ShapeCache.getShape("3");
主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。
- 主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
以随机获取多种形状为例,共分四步:
1、创建一个接口。
publicinterfaceShape{voiddraw()}
2、创建实现接口的实体类。
publicclassCircleimplementsShape{privateStringcolor; privateintx; privateinty; privateintradius; publicCircle(Stringcolor){this.color = color} publicvoidsetX(intx){this.x = x} publicvoidsetY(inty){this.y = y} publicvoidsetRadius(intradius){this.radius = radius} @Overridepublicvoiddraw(){Log.e("---", "Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius)} }
3、创建一个工厂,生成基于给定信息的实体类的对象。
publicclassShapeFactory{privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>(); publicstaticShapegetShape(Stringcolor){Shapeshape = circleMap.get(color); if (shape == null){shape = newCircle(color); circleMap.put(color, shape); Log.e("getShape", "Creating circle of color : " + color)} returnshape} }
4、使用该工厂,通过传递颜色信息来获取实体类的对象。
for (inti = 0; i < 20; i++){Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw()}
一个类代表另一个类的功能。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。可以理解为内存中没有这个对象就创建,有就直接返回这个对象。
- 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
以获取磁盘中的图片为例,总共分三步:
1、创建一个接口。
publicinterfaceImage{voiddisplay()}
2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。
publicclassRealImageimplementsImage{privateStringfileName; publicRealImage(StringfileName){this.fileName = fileName; loadFromDisk(fileName)} privatevoidloadFromDisk(StringfileName){Log.e("RealImage", "loading " + fileName)} @Overridepublicvoiddisplay(){Log.e("RealImage", "Displaying " + fileName)} }
publicclassProxyImageimplementsImage{privateStringfileName; privateRealImagerealImage; publicProxyImage(StringfileName){this.fileName = fileName} @Overridepublicvoiddisplay(){if (realImage == null){realImage = newRealImage(fileName)} realImage.display()} }
3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
Imageimage = newProxyImage("test_10mb.png"); // 第一次是new的,图像从磁盘加载image.display(); // 第二次取缓存,图像不需要从磁盘加载image.display();
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
- 主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
以画不同颜色的圆为例,实现共分五步:
1、创建桥接实现接口。
publicinterfaceDrawAPI{voiddrawCircle(intradius, intx, inty)}
2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircle、GreenCircle
publicclassRedCircleimplementsDrawAPI{@OverridepublicvoiddrawCircle(intradius, intx, inty){Log.e("---", "Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", " + y + "]")} }
3、使用 DrawAPI 接口创建抽象类 Shape。
publicabstractclassShape{protectedDrawAPIdrawAPI; protectedShape(DrawAPIdrawAPI){this.drawAPI = drawAPI} publicabstractvoiddraw()}
4、创建实现了 Shape 接口的实体类。
publicclassCircleextendsShape{privateintx, y, radius; protectedCircle(intx, inty, intradius, DrawAPIdrawAPI){super(drawAPI); this.x = x; this.y = y; this.radius = radius} @Overridepublicvoiddraw(){drawAPI.drawCircle(radius, x, y)} }
5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。
// 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw(); // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle()); circle2.draw();
又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
- 主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
以创建和打印员工的层次结构为例,最小单元示例:
1、创建 Employee 类,该类带有 Employee 对象的列表。
publicclassEmployee{privateStringname; // 部门privateStringdept; // 工资privateintsalary; // 员工 listprivateList<Employee> subordinates; publicEmployee(Stringname, Stringdept, intsalary){this.name = name; this.dept = dept; this.salary = salary; this.subordinates = newArrayList<Employee>()} publicvoidadd(Employeee){subordinates.add(e)} publicvoidremove(Employeee){subordinates.remove(e)} publicList<Employee> getSubordinates(){returnsubordinates} @OverridepublicStringtoString(){return"Employee{" + "name='" + name + '\'' + ", dept='" + dept + '\'' + ", salary=" + salary + ", subordinates=" + subordinates + '}'} }
2.使用 Employee 类来创建和打印员工的层次结构。
finalEmployeeceo = newEmployee("John", "CEO", 30000); EmployeeheadSales = newEmployee("Robert", "Head sales", 20000); EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000); Employeeclerk1 = newEmployee("Laura", "Marketing", 10000); Employeeclerk2 = newEmployee("Bob", "Marketing", 10000); EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000); EmployeesalesExecutive2 = newEmployee("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=[]}]}]} */
Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式属于行为型模式。
- 主要解决:不同的方式来遍历整个整合对象。
以使用迭代器打印名字为例,总共分三步:
1、创建接口:
publicinterfaceIterator{publicbooleanhasNext(); publicObjectnext()}
publicinterfaceContainer{publicIteratorgetIterator()}
2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。
publicclassNameRepositoryimplementsContainer{privateStringnames[] ={"John", "jingbin", "youlookwhat", "lookthis"}; @OverridepublicIteratorgetIterator(){returnnewNameIterator()} privateclassNameIteratorimplementsIterator{intindex; @OverridepublicbooleanhasNext(){if (index < names.length){returntrue} returnfalse} @OverridepublicObjectnext(){if (hasNext()){returnnames[index++]} returnnull} } }
3、使用 NameRepository 来获取迭代器,并打印名字。
NameRepositorynameRepository = newNameRepository(); for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ){Stringname = (String) iterator.next(); Log.e("---", name); /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */ }
用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
- 主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
以公共聊天室为例,最小单元示例步骤:
1、创建中介类。
publicclassCharRoom{publicstaticvoidshowMessage(Useruser, Stringmessage){Log.e("---", newDate().toString() + " [" + user.getName() + "] : " + message)} }
2、创建 user 类。
publicclassUser{privateStringname; publicUser(Stringname){this.name = name} publicStringgetName(){returnname} publicvoidsetName(Stringname){this.name = name} publicvoidsendMessage(Stringmessage){// 使用中介类CharRoom.showMessage(this, message)} }
3、使用 User 对象来显示他们之间的通信。
Userjingbin = newUser("jingbin"); jingbin.sendMessage("Hi~ youlookwhat!"); //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat"); jingbin.sendMessage("Hi~ jingbin!"); //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。
- 主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
以使用备忘录为例,最小单元步骤:
1、创建 备忘录 Memento 类。
publicclassMemento{privateStringstate; publicMemento(Stringstate){this.state = state} publicStringgetState(){returnstate} publicvoidsetState(Stringstate){this.state = state} }
2、创建 Originator 类。
publicclassOriginator{privateStringstate; publicStringgetState(){returnstate} publicvoidsetState(Stringstate){this.state = state} publicMementosetSateToMemento(){returnnewMemento(state)} publicStringgetStateFromMemento(Mementomemento){returnmemento.getState()} }
3、创建 CareTaker 类。
publicclassCareTaker{privateList<Memento> mementoList = newArrayList<Memento>(); publicvoidadd(Mementomemento){mementoList.add(memento)} publicMementoget(intindex){returnmementoList.get(index)} }
4、使用 CareTaker 和 Originator 对象。
// 管理者CareTakercareTaker = newCareTaker(); Originatororiginator = newOriginator(); 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()); // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0)); Log.e("---", "First Saved State: " + fromMemento1); StringfromMemento2 = 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 */
提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
- 主要解决:对于一些固定文法构建一个解释句子的解释器。
以解释一句话为例,最小单元步骤:
1、创建一个表达式接口 Expression。
publicinterfaceExpression{publicbooleaninterpreter(Stringcontent)}
2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。
publicclassTerminalExpressionimplementsExpression{privateStringdata; publicTerminalExpression(Stringdata){this.data = data} @Overridepublicbooleaninterpreter(Stringcontent){// 是包含判断returncontent.contains(data)} }
publicclassOrExpressionimplementsExpression{privateExpressionexpression1; privateExpressionexpression2; publicOrExpression(Expressionexpression1, Expressionexpression2){this.expression1 = expression1; this.expression2 = expression2} @Overridepublicbooleaninterpreter(Stringcontent){returnexpression1.interpreter(content) || expression2.interpreter(content)} }
publicclassAndExpressionimplementsExpression{privateExpressionexpression1; privateExpressionexpression2; publicAndExpression(Expressionexpression1, Expressionexpression2){this.expression1 = expression1; this.expression2 = expression2} @Overridepublicbooleaninterpreter(Stringcontent){returnexpression1.interpreter(content) && expression2.interpreter(content)} }
3、使用 Expression 类来创建规则,并解析它们。
/** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression(){TerminalExpressionjingbin = newTerminalExpression("jingbin"); TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat"); returnnewOrExpression(jingbin, youlookwhat)} /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression(){TerminalExpressionjulie = newTerminalExpression("Julie"); TerminalExpressionmarried = newTerminalExpression("Married"); returnnewAndExpression(julie, married)} ExpressionmaleExpression = getMaleExpression(); // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin")); ExpressionwomanExpression = getMarriedWomanExpression(); // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
- 主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
以Android Studio中打印日志为例,最小单元步骤:
1、创建抽象的记录器类 AbstractLogger。
publicabstractclassAbstractLogger{publicstaticintINFO = 1; publicstaticintDEBUG = 2; publicstaticintERROR = 3; protectedintlevel; // 责任链中的下一个元素protectedAbstractLoggernextLogger; publicvoidsetNextLogger(AbstractLoggernextLogger){this.nextLogger = nextLogger} publicvoidlogMessage(intlevel, Stringmessage){if (this.level <= level){write(message)} // 递归效果,不断调用下一级 logMessageif (nextLogger != null){nextLogger.logMessage(level, message)} } protectedabstractvoidwrite(Stringmessage)}
2、创建扩展了该记录器类的实体类。
publicclassConsoleLoggerextendsAbstractLogger{publicConsoleLogger(intlevel){this.level = level} @Overrideprotectedvoidwrite(Stringmessage){Log.e("---", "Standard Console::Logger " + message)} }
publicclassFileLoggerextendsAbstractLogger{publicFileLogger(intlevel){this.level = level} @Overrideprotectedvoidwrite(Stringmessage){Log.e("---", "File::Logger " + message)} }
publicclassErrorLoggerextendsAbstractLogger{publicErrorLogger(intlevel){this.level = level} @Overrideprotectedvoidwrite(Stringmessage){Log.e("---", "Error Console::Logger " + message)} }
3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
publicstaticAbstractLoggergetChainOfLoggers(){ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR); FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG); ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO); errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); returnerrorLogger} AbstractLoggerlogger = 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.");
在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
- 主要解决:稳定的数据结构和易变的操作耦合问题。
以显示计算机的组成部分为例,主要分五步实现:
1、定义一个表示元素的接口。
publicinterfaceComputerPart{publicvoidaccept(ComputerPartVisitorcomputerPartVisitor)}
2、创建扩展了上述类的实体类。Keyboard、Monitor、Mouse、Computer
publicclassComputerimplementsComputerPart{privateComputerPart[] parts; publicComputer(){this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()}} @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor){for (ComputerPartpart : parts){part.accept(computerPartVisitor)} computerPartVisitor.visit(this)} }
publicclassMouseimplementsComputerPart{@Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor){computerPartVisitor.visit(this)} }
3、定义一个表示访问者的接口。
publicinterfaceComputerPartVisitor{publicvoidvisit(Computercomputer); publicvoidvisit(Mousemouse); publicvoidvisit(Keyboardkeyboard); publicvoidvisit(Monitormonitor)}
4、创建实现了上述类的实体访问者。
publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor{@Overridepublicvoidvisit(Computercomputer){Log.e("---", "Displaying Computer.")} @Overridepublicvoidvisit(Mousemouse){Log.e("---", "Displaying Mouse.")} @Overridepublicvoidvisit(Keyboardkeyboard){Log.e("---", "Displaying Keyboard.")} @Overridepublicvoidvisit(Monitormonitor){Log.e("---", "Displaying Monitor.")} }
5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
ComputerPartcomputer = newComputer(); computer.accept(newComputerPartDisplayVisitor()); /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

