行为模式:
(1)Chain of Responsibility-责任链模式
定义:使多个对象都有机会处理请求,从而避免了请求发送者和接受者的耦合关系.将这些对象链成一个链,并沿着该链依次向上发送请求,直到有对象处理该请求为止
来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去。
优点:
1. 实现了请求者与处理者代码分离,发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
2. 提高系统的灵活性和可扩展行。
缺点:
1. 每次都是从链头开始,这也正是链表的缺点,降低了性能,同时也给调试带来了很大的不便。你也许会想到一种貌似不错的解决方案,比如使用hash映射
2. 将要处理的请求id与处理类对象关联,但是这样系统损失了可扩展性。
应用场景:
1. 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定
2. 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
3. 可处理一个请求的对象集合应被动态指定
要沿着链转发请求,并保证接受者为隐式的,每个链上的对象都有一致的处理请求和访问链上后继者的接口(即如下实例中,在自己方法中再调用一次相同的方法)
如公司辞职,先让 项目经理PM处理,在让人事HR处理,最后让总裁CEO决定
//一个请求类,请求的名字和内容
public class Request {
private String name;
private String content;
public Request(String name, String content) {
super();
this.name = name;
this.content = content;
}
public String toString(){
return "name: "+name+"content: "+content;
}
}
//抽象一个处理接口,包含一个处理方法
public interface Handler {
public void handle(Request req);
}
//PM处理
public class PMHandler implements Handler {
private Handler h;
public PMHandler(Handler h) {
super();
this.h = h;
}
public void handle(Request req) {
System.out.println(req.toString()+" [项目经理审批]");
if(h ==null) return;
h.handle(req);
}
}
//HR处理
public class HRHandler implements Handler{
private Handler h;
public HRHandler(Handler h) {
super();
this.h = h;
}
public void handle(Request req) {
System.out.println(req.toString()+" [HR审批]");
if(h ==null) return;
h.handle(req);
}
}
//CEO处理
public class CEOHandler implements Handler{
private Handler h;
public CEOHandler(Handler h) {
super();
this.h = h;
}
public void handle(Request req) {
System.out.println(req.toString()+" [CEO审批]");
if(h ==null) return;
h.handle(req);
}
}
// 测试:
public class Client {
public static void main(String[] args) {
Request req = new Request("辞职","吃饭不方便!");
Handler handler = new PMHandler(new HRHandler(new CEOHandler(null)));
handler.handle(req);
}
}
name: 辞职content: 吃饭不方便! [项目经理审批]
name: 辞职content: 吃饭不方便! [HR审批]
name: 辞职content: 吃饭不方便! [CEO审批]
在最后的测试类中,生成具体的handler时,用多层包含的形式
//请求
public class Request {
private String content = "请求:";
public String getContent() {
return content;
}
public void setContent(String content) {
this.content += content;
}
}
//响应结果
public class Response {
private String result = "结果:";
public String getResult() {
return result;
}
public void setResult(String result) {
this.result += result;
}
}
//过滤器接口
public interface Filter {
public void doFilter(Request req, Response res, FilterChain chain);
}
//PM项目经理过滤处理
public class PMFilter implements Filter{
public void doFilter(Request req, Response res, FilterChain chain) {
req.setContent(" [PM 审批] ");//PM 处理
chain.doFilter(req, res, chain);//调用过滤器链chain中的下一个过滤器,所有的过滤器处理完请求后,才处理response响应结果
res.setResult(" [PM 同意] ");
}
}
//HR人事过滤处理
public class HRFilter implements Filter{
public void doFilter(Request req, Response res, FilterChain chain) {
req.setContent(" [HR 审批] ");
chain.doFilter(req, res, chain);
res.setResult(" [HR 同意] ");
}
}
//CEO过滤处理
public class CEOFilter implements Filter{
public void doFilter(Request req, Response res, FilterChain chain) {
req.setContent(" [CEO 审批] ");
chain.doFilter(req, res, chain);
res.setResult("[CEO 同意] ");
}
}
//过滤器链,里面有各种各样的处理过滤器
public class FilterChain implements Filter{
List<Filter> filters = new ArrayList<Filter>();
int index = 0; //记录当前执行到哪个过滤器
public FilterChain addFilter(Filter f){
this.filters.add(f);
return this;//返回当前对象,方便过滤器的添加
}
public void removeFilter(Filter f){
this.filters.remove(f);
}
public void doFilter(Request req, Response res, FilterChain chain) {
if(index == filters.size()) return;//判断是否是最后一个过滤器
Filter f = filters.get(index);
index ++;
f.doFilter(req, res, chain);
}
}
测试:
public class Client {
public static void main(String[] args) {
Request req = new Request();
req.setContent("辞职");
Response res = new Response();
FilterChain fc = new FilterChain();
fc.addFilter(new PMFilter())
.addFilter(new HRFilter())
.addFilter(new CEOFilter());
fc.doFilter(req, res, fc);
System.out.println(req.getContent());
System.out.println(res.getResult());
}
}
输出结果:
请求:辞职 [PM 审批] [HR 审批] [CEO 审批]
结果:[CEO 同意] [HR 同意] [PM 同意]
(2)Strategy-策略模式
定义:定义一组算法,将每个算法封装起来单独的类,可以使它们之间进行相互替换
优点:
1. 算法之间可以相互自由切换.
2. 避免使用多重条件判断.根据上下文来选择适合的算法.
3. 良好的可扩展性.可以很容易增加算法.
缺点:
1. 策略类数量比较多,可复用性小.
2. 所有策略都要对上层模块暴露.必须要知道有哪些策略,才能判断应该选择哪个算法.
应用场景:
1. 多个类只有在算法和行为上稍有不同.
2. 算法需要进行切换的场景.
3. 需要屏蔽算法规则的.只需要算法名字,就可以使用算法.
策略模式,就是将一个算法的不同实现封装成一个个单独的类,这些类实现同一个接口,使用者直接使用该接口来访问具体的算法。
这个样子,使用者就可以使用不同的算法来实现业务逻辑了。
一个音乐播放器,暂时支持Mp3、WMA、Ogg三种格式。当播放音乐时,要对歌曲文件进行解码,那么就需要用相应的解码算法。
解码算法就是抽象的策略,相应的格式解码算法就是具体策略
//抽象策略,解码接口
public interface IDdecode {
public void decode();//解码
}
//具体策略,几种解码算法,实现接口
//Mp3解码算法
public class Mp3Decode implements IDdecode {
public void decode() {
System.out.println("Mp3格式文件正在解码...");
}
}
//Wma解码算法
public class WmaDecode implements IDdecode{
public void decode() {
System.out.println("Wma格式文件正在解码...");
}
}
//Ogg解码算法
public class OggDecode implements IDdecode{
public void decode() {
System.out.println("Ogg格式文件正在解码...");
}
}
//解码器
public class Decoder {
IDdecode idDecode;
public Decoder(IDdecode idDecode){
this.idDecode = idDecode;
}
public void decode(){
this.idDecode.decode();
}
}
// 测试:应用环境:播放器
public class Client {
public static void main(String[] args){
Decoder decoder = null;
//Mp3解码
decoder = new Decoder(new Mp3Decode());
decoder.decode();
//Wma解码
decoder = new Decoder(new WmaDecode());
decoder.decode();
//Ogg解码
decoder = new Decoder(new OggDecode());
decoder.decode();
}
}
输出结果:
Mp3格式文件正在解码...
Wma格式文件正在解码...
Ogg格式文件正在解码...
(3)State-状态模式
定义:允许一个对象在其内部状态发生改变时,拥有不同的行为,看起来就好像变成另外一个类一样.
不同的状态,不同的行为; 或者说,每个状态有着相应的行为
优点:
1. 结构清晰.避免了过多的if…else…语句
2. 遵循了设计原则.良好地遵循了单一职责原则和开闭原则.
3. 良好的封装性.状态的改变放在对象内部实现.
缺点:
子类太多,会造成类膨胀.每一个状态都为一个类,在多状态的情况下,子类有很多.
应用场景:
1. 状态的切换
2. 行为会随着状态的改变而改变的对象.
3. 条件,分支判断语句的替代.
一个state,包括两部分: 对象 + 对象内部的属性(属性接口+具体属性)
一个对象,要有其属性,以及其setter,getter.且设置好其初始状态+一个调用显示状态的方法(里面就是状态调用自身的显示方法).
一个属性接口,应该有一个执行的方法.
一个具体属性,须包含对象进去,实现方法中,须设置对象下一个要显示的属性–>从而在对象下次调用方法时,其属性值会变化.
如红绿灯的切换,灯 有三种状态 红 、 黄 、绿
//灯对象
public class Light {
private Color color;
public Light(){
color = new RedColor(this);
}
public void showColor(){
color.show();
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
//抽象一个状态接口
public interface Color {
public void show();
}
public class RedColor implements Color{
private Light l;
public RedColor(Light l) {
super();
this.l = l;
}
public void show() {
System.out.println("红灯--车辆停!3s");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
l.setColor(new GreenColor(l));
}
}
public class GreenColor implements Color {
private Light l;
public GreenColor(Light l) {
super();
this.l = l;
}
public void show() {
System.out.println("绿灯--车辆行!3s");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
l.setColor(new YellowColor(l));
}
}
public class YellowColor implements Color {
private Light l;
public YellowColor(Light l) {
super();
this.l = l;
}
public void show() {
System.out.println("黄灯--马上要红灯车辆等!2s");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
l.setColor(new RedColor(l));
}
}
// 测试:
public class Client {
public static void main(String[] args){
Light light = new Light();//默认为红灯
//初始调用为红灯
light.showColor();
//再调用为绿灯
light.showColor();
//再调用为黄灯
light.showColor();
//不断调用,不断循环
light.showColor();
System.out.println("不断调用,不断循环");
}
}
输出结果:
红灯--车辆停!3s
绿灯--车辆行!3s
黄灯--马上要红灯车辆等!2s
红灯--车辆停!3s
不断调用,不断循环
(4) Observer-观察者模式
定义:对象中定义了一种1对多的依赖关系,使得当其所以赖的对象的状态改变时,各个对象可以自动地接收到通知,并进行更新.
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
优点:
1. 降低了程序的耦合性.把观察者与被观察者分离,并将二者间的关系通过抽象观察者和抽象被观察者联系在一起,当一方发生变化时不会影响另一方的执行。
2. 可以支持多种不同的具体观察者实现,有利于程序的扩展。
3. 以注册的方式添加和移除观察者,观察者的数目是可变的,可以动态的增加或移除观察者对象。
4. 建立一套触发机制.把单一职责的类串联起来.
缺点:
1. 很多个观察者时,执行效率比较低.
2. 多级触发将使代码非常复杂.
应用场景:
1. 观察者模式,用于存在一对多依赖关系的对象间,当被依赖者变化时,通知依赖者全部进行更新。因此,被依赖者,应该
有添加/删除依赖者的方法,且可以将添加的依赖者放到一个容器中;且有一个方法去通知依赖者进行更新
2. 关联行为场景. 3. 事件多级触发场景. 4. 跨系统的消息交换.
建立目标(subject)与观察者(observer)接口:
目标(subject)接口:
建立一个注册观察者对象的接口; public void attach(Observer o);
建立一个删除观察者对象的接口; public void detach(Observer o);
建立一个当目标状态发生改变时,发布通知给观察者对象的接口; public void notice();
观察者(observer)接口:
建立一个当收到目标通知后的更新接口: public void update();
当商品的价格变动时,及时通知会员
public interface Subject {
public void attach(Observer o);
public void detach(Observer o);
public void notice();
}
public interface Observer {
public void update();
}
public class Commodity implements Subject{
private String name;
private int price;
private ArrayList<Observer> observers;
public Commodity(){
observers = new ArrayList<Observer>();
}
public void attach(Observer o) {
observers.add(o);
}
public void detach(Observer o) {
observers.remove(o);
}
public void notice() {
for(int i=0; i<observers.size(); i++){
observers.get(i).update();
}
}
public void setPrice(int price) {
this.price = price;
notice();//重点
}
}
public class Consumer implements Observer{
private String name;
private int price;
private Commodity commodity;
public Consumer(String name, Commodity commodity) {
super();
this.name = name;
this.commodity = commodity;
}
public void update() {
price = commodity.getPrice();
}
public void show(){
System.out.println("name: "+name+"--commodity price: "+price);
}
}
public class Client {
public static void main(String[] args) {
Commodity com = new Commodity();
for(int i=0; i<5; i++){
Consumer c = new Consumer("consumer"+i,com);
com.getObservers().add(c);
}
com.setPrice(100);
for(int i=0; i<5; i++){
((Consumer)com.getObservers().get(i)).show();
}
com.setPrice(200);
for(int i=0; i<5; i++){
((Consumer)com.getObservers().get(i)).show();
}
}
}
(5)Template-模板模式
定义:定义一个算法的操作的框架,而将其具体实现推迟到子类.使得子类而不能修改算法的结构.
优点:
1. 封装不变性,扩展可变性.
2. 提取公共代码,便于维护.
3. 父类控制行为,子类实现.
缺点:
模板方法是基于继承方式实现的,所以对于可变方法较多的场景需要提供很多子类,这样会导致类的数量增加,系统变得庞大而不好维护
应用场景:
1. 多个子类有公共方法,并且逻辑基本相同.
2. 重复,复杂的算法可以提取到父类,周边相关的细节功能可以由子类实现.
3. 控制子类扩展.
public abstract class Template {
public abstract void open();
public abstract void print();
public abstract void close();
public final void display(){//final保证子类不会修改
open();//先open...
for(int i=0; i<5; i++){//反复输出5次
print();
}
close();//输出完毕
}
}
public class CharTemplate extends Template{
private char ch;//要输出的字符
public CharTemplate(char ch) {
super();
this.ch = ch;
}
@Override
public void close() {
System.out.println(">>");
}
@Override
public void open() {
System.out.print("<<");
}
@Override
public void print() {
System.out.print(ch);
}
}
public class StringTemplate extends Template{
private String str;
private int width;
public StringTemplate(String str) {
super();
this.str = str;
width = str.getBytes().length;
}
@Override
public void close() {
printLine();
}
@Override
public void open() {
printLine();
}
@Override
public void print() {
System.out.println("|"+str+"|");
}
public void printLine(){
System.out.print("+"); //输出"+"号表示边框位置
for(int i=0; i < width; ++i) {
System.out.print("-"); //当作线段
}
System.out.println("+"); //输出"+"号表示边框位置
}
}
// 测试:
public class Client {
public static void main(String[] args) {
Template tem = new CharTemplate('A');
tem.display();
tem = new StringTemplate("Hello world");
tem.display();
}
}
<<AAAAA>>
+-----------+
|Hello world|
|Hello world|
|Hello world|
|Hello world|
|Hello world|
+-----------+