96SEO 2026-02-19 15:47 0
Pattern)在一个抽象类公开定义了执行它的方法的模板。

它的子类可以按需要重写方法实现但调用将以抽象类中定义的方式进行。
简单说模板方法模式定义一个操作中的算法的骨架而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构就可以重定义该算法的某些特定步骤这种类型的设计模式属于行为型模式。
类中实现了模板方法(template)定义了算法的骨架具体子类需要去实现
选材---添加配料---浸泡---放到豆浆机打碎通过添加不同的配料可以制作出不同口味的豆浆选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的请使用
选材---添加配料---浸泡---放到豆浆机打碎通过添加不同的配料可以制作出不同口味的豆浆
选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的(红豆、花生豆浆。
。
。
)思路分析和图解(类图)
make(){select();addCondiments();soak();beat();}//选材void
select(){System.out.println(第一步选择好的新鲜黄豆);}//添加不同配料子类具体实现abstract
soak(){System.out.println(第三步黄豆和配料开始浸泡需要3个小时);}//打豆浆void
beat(){System.out.println(第四步黄豆和配料放到豆浆机去打碎);}}
{System.out.println(第二步加入上等红豆);}
{System.out.println(第二步加入上好的花生);}
{System.out.println(--------制作红豆豆浆--------);SoyaMilk
RedBeanSoyaMilk();soyaMilk.make();System.out.println(--------制作红豆豆浆--------);SoyaMilk
PeanutSoyaMilk();peanutSoyaMilk.make();}
在模板方法模式的父类中我们可以定义一个方法它默认不做任何事子类可以视情况要不要覆盖它该方法称为“钩子”。
还是用上面做豆浆的例子来讲解比如我们还希望制作纯豆浆不添加任何的配料请使用钩子方法对前面的模板方法进行改造
{addCondiments();}soak();beat();}...//钩子方法决定是否需要添加配料boolean
main(...){System.out.println(--------制作纯豆浆--------);SoyaMilk
PureSoyaMilk();pureSoyaMilk.make();//输出--------制作纯豆浆--------第一步选择好的新鲜黄豆第三步黄豆和配料开始浸泡需要3个小时第四步黄豆和配料放到豆浆机去打碎
绘制view内容dispatchDraw(canvas);//步骤4.
{mOverlay.getOverlayView().dispatchDraw(canvas);}onDrawForeground(canvas);
View的draw()方法中定义了一整套的绘制流程这个流程是固定的所有的Android中的View都是按照这个流程来绘制的。
其中drawBackground()这个方法在View类中是实现了具体过程的而onDraw()方法和dispatchDraw()方法在View中都是空实现即都是钩子方法。
不同的子类通过重写这些空实现来实现自身不同的绘制效果。
具体的View像TextView这些单一的View就会重写onDraw()方法由于TextView没有子View所以dispatchDraw()还是空实现而ViewGroup类含有子View需要遍历子View并绘制因此需要重写onDraw()和dispatchDraw()。
所以我们自定义View时必须且只需重写onDraw自定义ViewGroup时则需要重写onDraw()和dispatchDraw()。
基本思想是算法只存在于一个地方也就是在父类中容易修改。
需要修改算法时只要修改父类的模板方法或者已经实现的某些步骤子类就会继承这些修改实现了最大化代码复用。
父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
既统一了算法也提供了很大的灵活性。
父类的模板方法确保了算法的结构保持不变同时由子类提供部分步骤的实现。
该模式的不足之处每一个不同的实现都需要一个子类实现导致类的个数增加使得系统更加庞大一般模板方法都加上
防止子类重写模板方法.模板方法模式使用场景当要完成在某个过程该过程要执行一系列步骤
这一系列的步骤基本相同但其个别步骤在实现时可能不同通常考虑用模板方法模式来处理
Pattern在软件设计中我们经常需要向某些对象发送请求但是并不知道请求的接收者是谁也不知道被请求的操作是哪个
我们只需在程序运行时指定具体的请求接收者即可此时可以使用命令模式来进行设计命名模式使得请求发送者与请求接收者消除彼此之间的耦合让对象之间的调用关系更加灵活实现解耦。
在命令模式中会将一个请求封装为一个对象以便使用不同参数来表示不同的请求(即命名)同时命令模式也支持可撤销的操作。
通俗易懂的理解将军发布命令士兵去执行。
其中有几个角色将军命令发布者、士兵命令的具体执行者、命令(连接将军和士兵)。
是命令角色需要执行的所有命令都在这里可以是接口或抽象类Receiver:
接收者角色知道如何实施和执行一个请求相关的操作ConcreteCommand:
我们买了一套智能家电有照明灯、风扇、冰箱、洗衣机我们只要在手机上安装
就可以控制对这些家电工作。
这些智能家电来自不同的厂家我们不想针对每一种家电都安装一个
控制所有智能家电的需要则每个智能家电厂家都要提供一个统一的接口给
就可以考虑使用命令模式。
命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来.在我们的例子中动作的请求者是手机
{receiver.off();}Overridepublic
on(){System.out.println(开灯请睁眼);}public
off(){System.out.println(关灯请闭眼);}
no){onCommands[no].execute();undoCommand
no){offCommands[no].execute();undoCommand
undoButtonClicked(){undoCommand.undo();}}
调用接收者的方法tv.off();}Overridepublic
调用接收者的方法tv.on();}Overridepublic
LightReceiver();//创建电灯的开关命令ICommand
LightOnCommand(receiver);ICommand
LightOffCommand(receiver);//创建遥控器RemoteController
RemoteController();//给遥控器设置相关命令controller.setCommand(0,onCommand,offCommand);System.out.println(----按下开灯按钮----);controller.onButtonClicked(0);System.out.println(----按下关灯按钮----);controller.offButtonClicked(0);System.out.println(----按下撤销按钮----);controller.undoButtonClicked();System.out.println(----------开始操作电视机----------);TVReceiver
TVOnCommand(tvReceiver);ICommand
TVOffCommand(tvReceiver);controller.setCommand(1,tvOnCommand,tvOffCommand);controller.onButtonClicked(1);controller.offButtonClicked(1);controller.undoButtonClicked();}
实际上Thread的使用就是一个简单的命令模式先看下Thread的使用
Thread的start()方法即命令的调用者同时Thread的内部会调用Runnable的run()这里Thread又
充当了具体的命令角色最后的Runnable则是接受者了负责最后的功能处理。
另一个比较典型的常用到命令模式就是Handler了这里就不贴代码了简单分析下各个类的角
接收者Handler执行消息的处理操作。
调用者Looper调用消息的的处理方法。
命令角色Message消息类。
将发起请求的对象与执行请求的对象解耦。
发起请求的对象是调用者调用者只要调用命令对象的execute()方法就可以让接收者工作而不必知道具体的接收者对象是谁、是如何实现的命令对象会负责让接收者执行请求的动作也就是说”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的命令对象起到了纽带桥梁的作用。
容易设计一个命令队列。
只要把命令对象放到列队就可以多线程的执行命令容易实现对请求的撤销和重做命令模式不足可能导致某些系统有过多的具体命令类增加了系统的复杂度这点在在使用的时候要注意空命令也是一种设计模式它为我们省去了判空的操作。
在上面的实例中如果没有用空命令我们每按下一个按键都要判空这给我们编码带来一定的麻烦。
命令模式经典的应用场景界面的一个按钮都是一条命令、模拟
Pattern封装一些作用于某种数据结构的各元素的操作它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
主要将数据结构与数据操作分离解决数据结构和操作耦合性问题访问者模式的基本工作原理是在被访问的类里面加一个对外提供接待访问者的接口访问者模式主要应用场景是需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联)同时需要避免让这些操作污染这些对象的类可以选用访问者模式解决
声明的操作是每个操作实现的部分.ObjectStructure
将观众分为男人和女人对歌手进行测评当看完某个歌手表演后得到他们对该歌手不同的评价(评价
将人分为男人和女人对歌手进行测评当看完某个歌手表演后得到他们对该歌手不同的评价(评价
{System.out.println(man.getName(),这个男人给的评价是很成功);}Overridevoid
{System.out.println(woman.getName(),这个女人给的评价是很成功);}
{System.out.println(man.getName(),这个男人给的评价是失败了);}Overridevoid
{System.out.println(woman.getName(),这个女人给的评价是失败了);}
这里使用到了双分派即首先在客户端程序中将具体的状态作为参数传递到Woman或者Man中第一次分派*
然后Woman类调用了作为参数的具体方法中方法getWomanResult同时将自己this作为参数传入完成了第二次分派*/
person){persons.add(person);}//删除public
person){persons.remove(person);}//显示测评结果public
{//创建objectStructureObjectStructure
ObjectStructure();objectStructure.attach(new
Man(张三));objectStructure.attach(new
Man(李四));objectStructure.attach(new
Success();objectStructure.display(success);//失败Action
Fail();objectStructure.display(fail);}
上面提到了双分派所谓双分派是指不管类怎么变化我们都能找到期望的方法运行。
双分派意味着得到执行的操作取决于请求的种类和两个接收者的类型以上述实例为例假设我们要添加一个
{System.out.println(man.getName(),这个男人给的评价是待定);}Overridevoid
{System.out.println(woman.getName(),这个女人给的评价是待定);}
Wait();objectStructure.display(wait);
访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高访问者模式可以对功能进行统一可以做报表、UI、拦截器与过滤器适用于数据结构相对稳定的系统缺点具体元素对访问者公布细节也就是说访问者关注了其他类的内部细节这是迪米特法则所不建议的,
这样造成了具体元素变更比较困难违背了依赖倒转原则。
访问者依赖的是具体元素而不是抽象元素因此如果一个系统有比较稳定的数据结构又有经常变化的功能需求那么访问者模式就是比较合适的.
Pattern是常用的设计模式属于行为型模式如果我们的集合元素是用不同的方式实现的有数组还有
的集合类或者还有其他方式当客户端要遍历这些集合元素的时候就要使用多种遍历方式而且还会暴露元素的内部结构可以考虑使用迭代器模式解决。
迭代器模式提供一种遍历集合元素的统一接口用一致的方法遍历集合元素不需要知道集合对象的底层表示即不暴露其内部的结构。
编写程序展示一个学校院系结构需求是这样要在一个页面中展示出学校的院系组成一个学校
将学院看做是学校的子类系是学院的子类这样实际上是站在组织大小来进行分层次的实际上我们的要求是在一个页面中展示出学校的院系组成一个学校有多个学院一个学院有多个系因此这种方案不能很好实现的遍历的操作解决方案
编写程序展示一个学校院系结构需求是这样要在一个页面中展示出学校的院系组成一个学校有多个学院
departmentList;//信息工程学院是以List方式存放系int
InfoCollegeIterator(ListDepartment
(indexdepartmentList.size()-1){return
departmentList.get(index);return
department;}//删除方法默认空实现Overridepublic
ComputerCollegeIterator(Department[]
(positiondepartments.length||departments[position]null){return
department;}//删除方法默认空实现Overridepublic
Department[5];addDepartment(Java,java专业);addDepartment(PHP,PHP专业);addDepartment(大数据,大数据专业);}Overridepublic
Department(name,desc);departments[numOfDepartment]
ComputerCollegeIterator(departments);}
departmentList;//信息工程学院是以List方式存放系int
InfoCollegeIterator(ListDepartment
(indexdepartmentList.size()-1){return
departmentList.get(index);return
department;}//删除方法默认空实现Overridepublic
printCollege(){//从collegeList去除所有学院//java
中的List已经实现了iteratorIteratorCollege
(College)iterator.next();System.out.println(c.getName());printDepartment(c.createIterator());}}//输出
(iterator.hasNext()){Department
(Department)iterator.next();System.out.println(d.getName()
ComputerColleage();InfoColleage
InfoColleage();collegeList.add(computerColleage);collegeList.add(infoColleage);OutputImpl
OutputImpl(collegeList);output.printCollege();}
ArrayList();a.add(jack);a.add(tom);IteratorString
(iterator.hasNext()){System.out.println(iterator.next());}}
提供一个统一的方法遍历对象客户不用再考虑聚合的类型使用一种方法就可以遍历对象了。
隐藏了聚合的内部结构客户端要遍历聚合的时候只能取到迭代器而不会知道聚合的具体组成。
提供了一种设计思想就是一个类应该只有一个引起变化的原因叫做单一责任原则。
在聚合类中我们把迭代器分开就是要把管理对象集合和遍历对象集合的责任分开这样一来集合改变的话只影响到聚合对象。
而如果遍历方式改变的话只影响到了迭代器。
当要展示一组相似对象或者遍历一组相同对象时使用,
观察者模式类似订牛奶业务奶站/气象局Subject用户/第三方网站Observer
通知所有的注册的用户根据不同需求可以是更新数据让用户来取也可能是实施推送
看具体需求定Observer接收输入观察者模式对象之间多对一依赖的一种设计方案被依赖的对象为
气象站可以将每天测量到的温度湿度气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。
需要设计开放型
API便于其他第三方也能接入气象站获取数据。
提供温度、气压和湿度的接口测量数据更新时要能实时的通知给第三方
***);System.out.println(***Today
***);System.out.println(***Today
currentConditions;//加入新的第三方public
updatecurrentConditions.update(getTemperature(),
currentConditionsdataChange();}
currentConditionsCurrentConditions
WeatherData(currentConditions);//更新天气情况weatherData.setData(30,
40);//天气情况变化System.out.println(天气情况变化);weatherData.setData(40,
其他第三方接入气象站获取数据的问题无法在运行时动态的添加第三方
中当增加一个第三方都需要创建一个对应的第三方的公告板对象并加入到
{notifyObservers();}Overridepublic
{observers.add(observer);}Overridepublic
(observers.contains(observer)){observers.remove(observer);}}Overridepublic
{observer.update(getTemperature(),getPressure(),getHumidity());}}}
***);System.out.println(***Today
***);System.out.println(***Today
***);System.out.println(***百度数据
***);System.out.println(***百度数据
BaiduSite();//注册到weatherDatasubject.registerObserver(observer);subject.registerObserver(observer2);//通知各个注册的观察者((WeatherData)subject).setData(10f,20f,30f);}
{//构造函数初始化一个观察者list来保存观察者observers
ArrayList();}//添加观察者带同步字段的所以是线程安全的public
{observers.add(o);}}//删除观察者public
{observers.remove(o);}//通知所以观察者无参数public
{notifyObservers(null);}//通知所有观察者带参数public
arrLocal;//加synchronized字段保证多线程下操作没有问题synchronized
(!hasChanged())//这里做了是否发生改变的判断是为了防止出现无意义的更新return;arrLocal
Observer[observers.size()]);//ArrayList转换成一个临时的数组这样就防止了通知添加移除同时发生可能导致的异常clearChanged();///清除改变状态设置为false}//遍历逐一通知for
{observers.clear();}//设置被观察者为改变状态设置为trueprotected
true;}//清除改变状态设置为falseprotected
观察者模式设计后会以集合的方式来管理用户(Observer)包括注册移除和通知。
这样我们增加观察者(这里可以理解成一个新的公告板)就不需要去修改核心类
原则。
解除观察者与主题之间的耦合。
让耦合的双方都依赖于抽象而不是依赖具体。
从而使得各自的变化都不会影响另一边的变化。
易于扩展对同一主题新增观察者时无需修改原有代码。
依赖关系并未完全解除抽象主题仍然依赖抽象观察者。
使用观察者模式时需要考虑一下开发效率和运行效率的问题程序中包括一个被观察者、多个观察者开发、调试等内容会比较复杂而且在Java中消息的通知一般是顺序执行那么一个观察者卡顿会影响整体的执行效率在这种情况下一般会采用异步实现。
可能会引起多余的数据通知。
Pattern用一个中介对象来封装一系列的对象交互。
中介者使各个对象不需要显式地相互引用从而使其耦合松散而且可以独立地改变它们之间的交互中介者模式属于行为型模式使代码易于维护比如
就是抽象中介者,定义了同事对象到中介者对象的接口Colleague
HashMap,并接受某个同事对象消息完成相应的任务ConcreteColleague
等主人要看电视时各个设备可以协同工作自动完成看电视的准备工作比如流程为闹铃响起-咖啡机开始做咖啡-窗帘自动落下-电视机开始播放
当各电器对象有多种状态改变时相互之间的调用关系会比较复杂各个电器对象彼此联系你中有我我中有你不利于松耦合.各个电器对象之间所传递的消息(参数)容易混乱当系统增加一个新的电器对象时或者执行流程改变时代码的可维护性、扩展性都不理想考虑中介者模式
{this.GetMediator().GetMessage(stateChange,
{SendMessage(stateChange);}Overridepublic
{this.GetMediator().GetMessage(stateChange,
{this.GetMediator().GetMessage(stateChange,
minutes!);System.out.println(Coffee
{this.GetMediator().GetMessage(stateChange,
{colleagueMap.put(colleagueName,
colleagueName);}}//具体中介者的核心方法//1.
中介者在这个方法协调各个具体的同事对象完成任务Overridepublic
(colleagueMap.get(colleagueName)
(colleagueMap.get(interMap.get(CoffeeMachine)))).StartCoffee();((TV)
(colleagueMap.get(interMap.get(TV)))).StartTv();}
(colleagueMap.get(interMap.get(TV)))).StopTv();}}
(colleagueMap.get(colleagueName)
(colleagueMap.get(interMap.get(Curtains)))).UpCurtains();}
(colleagueMap.get(colleagueName)
(colleagueMap.get(colleagueName)
{//如果是以窗帘发出的消息这里处理...}}Overridepublic
getMessage会根据接收到的同事对象发出的消息来协调调用其它的同事对象
TV);//让闹钟发出消息alarm.SendAlarm(0);coffeeMachine.FinishCoffee();alarm.SendAlarm(1);}
多个类相互耦合会形成网状结构,使用中介者模式将网状结构分离为星型结构进行解耦减少类间依赖降低了耦合符合迪米特原则中介者承担了较多的责任一旦中介者出现了问题整个系统就会受到影响如果设计不当中介者对象本身变得过于复杂这点在实际使用时要特别注意
Pattern在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态。
这样以后就可将该对象恢复到原先保存的状态可以这里理解备忘录模式现实生活中的备忘录是用来记录某些要去做的事情或者是记录已经达成的共同意见的事情以防忘记了。
而在软件层面备忘录模式有着相同的含义备忘录对象主要用来记录一个对象的某种状态或者某些数据当要做回退时可以从备忘录对象里获取原来的数据进行恢复操作备忘录模式属于行为型模式
state;}//编写一个方法可以保存一个状态对象Memento//
Memento(state);}//通过备忘录对象恢复状态public
memento){mementoList.add(memento);}//获取到第index个Originator的备忘录对象public
Caretaker();originator.setState(
);//保存了当前的状态caretaker.add(originator.saveStateMemento());originator.setState(
);caretaker.add(originator.saveStateMemento());originator.setState(
);caretaker.add(originator.saveStateMemento());System.out.println(当前的状态是originator.getState());//希望恢复到状态1System.out.println(恢复到状态1originator.getStateFromMemento(caretaker.get(0)));}
这样当我们游戏的对象很多时不利于管理开销也很大.传统的方式是简单地做备份new
出另外一个对象出来再把需要备份的数据放到这个新对象但这就暴露了对象内部的细节解决方案
Memento(vit,def);}//恢复gameRole的状态public
recoverGameRoleFromMemento(Memento
memento.getDef();}//显示当前游戏角色的状态public
display(){System.out.println(游戏角色当前的攻击力this.vit当前游戏角色的防御力this.def);}}
GameRole();gameRole.setVit(100);gameRole.setDef(100);System.out.println(和boss大战前的状态);gameRole.display();//把当前状态保存caretakerCaretaker
Caretaker();caretaker.setMemento(gameRole.createMemento());System.out.println(和boss开始大战);gameRole.setDef(30);gameRole.setVit(30);gameRole.display();System.out.println(大战后使用备忘录恢复元气);gameRole.recoverGameRoleFromMemento(caretaker.getMemento());gameRole.display();}
给用户提供了一种可以恢复状态的机制可以使用户能够比较方便地回到某个历史的状态实现了信息的封装使得用户不需要关心状态的保存细节如果类的成员变量过多势必会占用比较大的资源而且每一次保存都会消耗一定的内存,
1、在编译原理中一个算术表达式通过词法分析器形成词法单元而后这些词法单元再通过语法
分析器构建语法分析树最终形成一颗抽象的语法分析树。
这里的词法分析器和语法分析器都可以
Pattern是指给定一个语言(表达式)定义它的文法的一种表示
应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树一些重复出现的问题可以用一种简单的语言来表达一个简单语法需要解释的场景
4、这样的例子还有比如编译器、运算表达式计算、正则表达式、机器人等
是环境角色,含有解释器之外的全局信息.AbstractExpression:
声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享TerminalExpression:
实现与文法中的终结符相关的解释操作NonTermialExpression:
编写一个方法接收表达式的形式然后根据用户输入的数值进行解析得到结果问题分析如果加入新的运算符比如
interpreter(HashMapString,Integer
抽象运算符号解析器这里每个运算符号都只和自己左右两个数字有关系*
但左右两个数字有可能也是一个解析的结果无论何种类型都是Expression类的实现类*/
是让他的子类来实现的因此interpreter是一个默认实现Overridepublic
super.left.interpreter(var)super.right.interpreter(var);}
super.left.interpreter(var)-super.right.interpreter(var);}
VarExpression(String.valueOf(charArray[i]));//
VarExpression(String.valueOf(charArray[i]));stack.push(new
VarExpression(String.valueOf(charArray[i])));break;}}//当遍历完整个
this.expression.interpreter(var);}}
Calculator(expStr);System.out.println(运算结果
{System.out.print(请输入表达式);return
InputStreamReader(System.in))).readLine();}//
(!map.containsKey(String.valueOf(ch)))
InputStreamReader(System.in))).readLine();map.put(String.valueOf(ch),
当有一个语言需要解释执行可将该语言中的句子表示为一个抽象语法树就可以考虑使用解释器模式
应用场景编译器、运算表达式计算、正则表达式、机器人等使用解释器可能带来的问题解释器模式会引起类膨胀、解释器模式采用递归调用方法将会导致调试非
Pattern它主要用来解决对象在多种状态转换时需要对外输出不同的行为的问题。
状态和行为是一一对应的状态之间可以相互转换当一个对象的内在状态改变时允许改变其行为这个对象看起来像是改变了其类
可以抽奖、不能抽奖、发放奖品和奖品领完活动的四个状态转换关系图(右图)
activity;}//已经扣除了积分不能再扣Overridepublic
{System.out.println(已经扣取过了积分);}//可以抽奖,
{System.out.println(正在抽奖请稍等);Random
contextactivity.setState(activity.getDispenseState());return
{System.out.println(很遗憾没有抽中奖品);//
改变状态为不能抽奖activity.setState(activity.getNoRafflleState());return
{System.out.println(没中奖不能发放奖品);}}public
初始化时传入活动引用扣除积分后改变其状态RaffleActivity
activity;}//当前状态是可以扣积分的扣除后将状态设置成抽象状态Overridepublic
积分成功您可以抽奖了);activity.setState(activity.getCanRaffleState());}Overridepublic
{System.out.println(扣了积分才能抽奖喔);return
初始化时传入活动引用发放奖品后改变其状态RaffleActivity
{System.out.println(不能扣除积分);}Overridepublic
{System.out.println(不能抽奖);return
改变状态为不能抽奖activity.setState(activity.getNoRafflleState());}
{System.out.println(很遗憾奖品发送完了);//
后面我们就不可以抽奖activity.setState(activity.getDispensOutState());//System.out.println(抽奖活动结束);//System.exit(0);}}
DispenseOutState(RaffleActivity
{System.out.println(奖品发送完了请下次再参加);}Overridepublic
{System.out.println(奖品发送完了请下次再参加);return
{System.out.println(奖品发送完了请下次再参加);}
DispenseOutState(this);//构造器//1.
{state.deduceMoney();}//抽奖public
{//领取奖品state.dispensePrize();}}public
state;}//这里请大家注意每领取一次奖品count--public
参加抽奖第一步点击扣除积分activity.debuctMoney();//
RuntimeException(操作流程不允许);//抽象类默认实现了
接口的所有方法//该类的所有方法其子类(具体的状态类)可以有选择的进行重写Overridepublic
StateEnum.FEED_BACKED.getValue();}
FeedBackState());}Overridepublic
StateEnum.GENERATE.getValue();}}public
FeedBackState());}Overridepublic
StateEnum.NOT_PAY.getValue();}}public
FeedBackState());}Overridepublic
StateEnum.PAID.getValue();}}public
NotPayState。
。
。
//至于应该变成哪个状态有流程图来决定context.setState(new
FeedBackState());}Overridepublic
StateEnum.PUBLISHED.getValue();}}public
PublishState());}Overridepublic
StateEnum.REVIEWED.getValue();}
getCurrentState();}Overridepublic
getCurrentState();}Overridepublic
getCurrentState();}Overridepublic
getCurrentState();}Overridepublic
state.notPeopleAcceptEvent(this);
getCurrentState();}Overridepublic
getCurrentState();}Overridepublic
getCurrentState();}Overridepublic
PublishStatecontext.setState(new
PublishState());System.out.println(context.getCurrentState());//
paycontext.acceptOrderEvent(context);//
paidcontext.payOrderEvent(context);//
{context.checkFailEvent(context);System.out.println(流程正常..);}
System.out.println(e.getMessage());//
代码有很强的可读性。
状态模式将每个状态的行为封装到对应的一个类中方便维护。
将容易产生问题的
语句删除了如果把每个状态的行为都放到一个类中每次调用方法时都要判断当前是什么状态不但会产出很多
语句而且容易出错符合“开闭原则”。
容易增删状态会产生很多类。
每个状态都要一个对应的类当状态过多时会产生很多类加大维护难度应用场景当一个事件或者对象有很多种状态状态之间会相互转换对不同的状态要求有不同的行为的时候
Pattern中定义算法族策略组分别封装起来让他们之间可以互相替换此模式让算法的变化独立于使用算法的客户这算法体现了几个设计原则第一、把变化的代码从不变的代码中分离出来第二、针对接口编程而不是具体类定义了策略接口第三、多用组合/聚合少用继承客户通过组合方式使用策略
的问题其实是继承带来的问题对类的局部改动尤其超类的局部改动会影响其他部分。
会有溢出效应为了改进
{System.out.println(自由飞翔飞翔能力max);}
GoodFlyBehavior();}Overridevoid
{System.out.println(野鸭子);}}public
{System.out.println(北京鸭);}}public
WildDuck();wildDuck.display();wildDuck.fly();PekingDuck
PekingDuck();pekingDuck.display();pekingDuck.fly();}
先看下面的图片我们去旅游选择出行模式有很多种可以骑自行车、可以坐汽车、可以坐火车、可以坐飞
作为一个程序猿开发需要选择一款开发工具当然可以进行代码开发的工具有很多可以选择
Idea进行开发也可以使用eclipse进行开发也可以使用其他的一些开发工具。
该模式定义了一系列算法并将每个算法封装起来使它们可以相互替换且算法的变化不会影响
使用算法的客户。
策略模式属于对象行为模式它通过对算法进行封装把使用算法的责任和算法
抽象策略Strategy类这是一个抽象角色通常由一个接口或抽象类实现。
此角色给出所有的具体策略类所需的接口。
具体策略Concrete
Strategy类实现了抽象策略定义的接口提供具体的算法实现或行为。
环境Context类持有一个策略类的引用最终给客户端调用。
一家百货公司在定年度的促销活动。
针对不同的节日春节、中秋节、圣诞节推出不同的促销活
{System.out.println(满200元减50元);}
{System.out.println(满1000元加一元换购任意200元以下商品);}
定义环境角色Context用于连接上下文即把促销活动推销给客户这里可以理解为销售员
userService;PostMapping(/login)public
loginReq){if(loginReq.getType().equals(account)){System.out.println(用户名密码登录);//执行用户密码登录逻辑return
if(loginReq.getType().equals(sms)){System.out.println(手机号验证码登录);//执行手机号验证码登录逻辑return
(loginReq.getType().equals(we_chat)){System.out.println(微信登录);//执行用户微信登录逻辑return
LoginResp();loginResp.setSuccess(false);System.out.println(登录失败);return
注意我们重点讲的是设计模式并不是登录的逻辑所以以上代码并没有真正的实现登录功能
业务层代码大量使用到了if...else在后期阅读代码的时候会非常不友好大量使用if...else性能也不高如果业务发生变更比如现在新增了QQ登录方式这个时候需要修改业务层代码违反了开闭原则
改造之后不在service中写业务逻辑让service调用工厂然后通过service传递不同的参数来获
具体的策略AccountGranter、SmsGranter、WeChatGranter
ConcurrentHashMap();Autowiredprivate
setApplicationContext(ApplicationContext
{loginTypeConfig.getTypes().forEach((k,
applicationContext.getBean(y));});}/***
granterPool.get(grantType);return
factory.getGranter(loginReq.getType());if(granter
LoginResp();loginResp.setSuccess(false);return
大家可以看到我们使用了设计模式之后业务层的代码就清爽多了如果后期有新的需求改动比如加入了QQ登录我们只需要添加对
其实像这样的需求在日常开发中非常常见场景有很多以下的情景都可以使用工厂模式策略模式解决比
(LegacyMergeSort.userRequested)legacyMergeSort(a,
comparator);System.out.println(Arrays.toString(data));
在Android中使用ListView时都需要设置一个Adapter而这个Adapter根据我们实际的需求可以
用ArrayAdapter、SimpleAdapter等等这里就运用到策略模式。
策略模式的关键是分析项目中变化部分与不变部分策略模式的核心思想是多用组合/聚合
少用继承用行为类组合而不是行为的继承。
更有弹性体现了“对修改关闭对扩展开放”原则客户端增加行为不用修改原有代码只要添加一种策略或者行为
改变它使它易于切换、易于理解、易于扩展需要注意的是每添加一个策略就要增加一个类当策略过多是会导致类数目庞大
责任链模式为请求创建了一个接收者对象的链(简单示意图)。
这种模式对请求的发送者和接收者进行解耦。
职责链模式通常每个接收者都包含对另一个接收者的引用。
如果一个对象不能处理该请求那么它会把相同的请求传给下一个接收者依此类推。
这种类型的设计模式属于行为型模式
(request.getPrice()5000){System.out.println(请求编号idrequest.getId()
{System.out.println(this.name无法处理交给上一级处理
approver.name);approver.processRequest(request);}}}public
(request.getPrice()5000request.getPrice()10000){System.out.println(请求编号idrequest.getId()
{System.out.println(this.name无法处理交给上一级处理
approver.name);approver.processRequest(request);}}
ViceSchoolMasterApprover(String
(request.getPrice()10000request.getPrice()30000){System.out.println(请求编号idrequest.getId()
{System.out.println(this.name无法处理交给上一级处理
approver.name);approver.processRequest(request);}}}public
(request.getPrice()30000){System.out.println(请求编号idrequest.getId()
{System.out.println(this.name无法处理交给下一级处理
approver.name);approver.processRequest(request);}}}
PurchaseRequest(1,1,13200);//创建相关的审批人DepartmentApprover
DepartmentApprover(主任);CollegeApprover
CollegeApprover(院长);ViceSchoolMasterApprover
ViceSchoolMasterApprover(副校长);SchoolMasterApprover
SchoolMasterApprover(校长);//需要将各个审批节点的下一级设置好departmentApprover.setApprover(collegeApprover);collegeApprover.setApprover(viceSchoolMasterApprover);viceSchoolMasterApprover.setApprover(schoolMasterApprover);schoolMasterApprover.setApprover(departmentApprover);//处理请求departmentApprover.processRequest(request);}
在现实生活中常常会出现这样的事例一个请求有多个对象可以处理但每个对象的处理条件或
例如公司员工请假可批假的领导有部门负责人、副总经理、总经理等但每个领导能批准的天
数不同员工必须根据自己要请假的天数去找不同的领导签名也就是说员工必须记住每个领导的
姓名、电话和地址等信息这增加了难度。
这样的例子还有很多如找领导出差报销、生活中
又名职责链模式为了避免请求发送者与多个请求处理者耦合在一起将所有请求的处理者通过前
一对象记住其下一个对象的引用而连成一条链当有请求发生时可将请求沿着这条链传递直到
比较常见的springmvc中的拦截器web开发中的filter过滤器
抽象处理者Handler角色定义一个处理请求的接口包含抽象处理方法和一个后继连接。
具体处理者Concrete
Handler角色实现抽象处理者的处理方法判断能否处理本次请求如果可以处理请求则处理否则将该请求转给它的后继者。
客户类Client角色创建处理链并向链头的具体处理者对象提交请求它不关心处理细节和请求的传递过程。
com.itheima.designpattern.chain;/***
com.itheima.designpattern.chain;import
{System.out.println(校验订单基本信息);//校验handler.process(order);}}/***
{System.out.println(补充订单信息);handler.process(order);}}/***
{System.out.println(计算金额-优惠券、VIP、活动打折);handler.process(order);}}/***
OrderValidition();//补充订单信息Handler
OrderAmountCalcuate();//订单落库Handler
OrderCreate();//设置责任链路orderValidition.setNext(orderFill);orderFill.setNext(orderAmountCalcuate);orderAmountCalcuate.setNext(orderCreate);//开始执行orderValidition.process(new
降低了对象之间的耦合度该模式降低了请求发送者和接收者的耦合度。
增强了系统的可扩展性可以根据需要增加新的请求处理类满足开闭原则。
增强了给对象指派职责的灵活性当工作流程发生变化可以动态地改变链内的成员或者修改它们的次序也可动态地新增或者删除责任。
责任链简化了对象之间的连接一个对象只需保持一个指向其后继者的引用不需保持其他所有处理者的引用这避免了使用众多的
语句。
责任分担每个类只需要处理自己该处理的工作不能处理的传递给下一个对象完成明确各类的责任范围符合类的单一职责原则。
不能保证每个请求一定被处理。
由于一个请求没有明确的接收者所以不能保证它一定会被处理该请求可能一直传到链的末端都得不到处理。
对比较长的职责链请求的处理可能涉及多个处理对象系统性能将受到一定影响。
职责链建立的合理性要靠客户端来保证增加了客户端的复杂性可能会由于职责链的错误设置而导致系统出错如可能会造成循环调用。
将请求和处理分开实现解耦提高系统的灵活性简化了对象使对象不需要知道链的结构性能会受到影响特别是在链比较长的时候因此需控制链中最大节点数量一般通过在
setNext()方法中判断是否已经超过阀值超过则不允许该链建立避免出现超长链无意识地破坏系统性能调试不方便。
采用了类似递归的方式调试时逻辑可能比较复杂最佳应用场景有多个对象可以处理同一个请求时比如多级请求、请假/加薪等审批流程、Java
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback