定义:
装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
举例说明:
今天我的朋友要和女生去约会,但是他在为要穿什么衣服而感到烦恼。这时我就发明了第一代衣服选择器:
首先我创建一个person类,有一个name属性,再将所有的衣服都分别写一个方法,在客户端只需创建对象然后一个个调用即可。但是这样衣服的代码都是写在一块了,不符合设计模式的开放-封闭原则。
后面我对代码进行改进,创建一个人类,创建一个服饰类,再让所有的衣服继承服饰类,但是这样我们穿衣的顺序就可以随意取值了。我可以像超人一样,先进穿衣服,在把S穿在外面,我们想要严格的控制穿衣的顺序,就必须再次进行改变
最终版:
person类:
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void Show() {
System.out.println("装扮的"+name);
}
}
服饰类:
public class Finery extends Person {
protected Person component;
public void Decorate(Person component) {
this.component = component;
}
public void Show() {
if (component != null) {
component.Show();
}
}
}
其他衣服类:
public class BigTrouser extends Finery {
public void Show(){
super.Show();
System.out.println("垮裤");
}
}
public class TShirts extends Finery {
public void Show(){
super.Show();
System.out.println("大T恤");
}
}
public class WearLeatherShoes extends Finery{
public void Show(){
super.Show();
System.out.println("皮鞋");
}
}
public class WearSneakers extends Finery {
public void Show(){
super.Show();
System.out.println("破球鞋");
}
}
public class WearSuit extends Finery{
public void Show(){
super.Show();
System.out.println("西装");
}
}
public class WearTie extends Finery {
public void Show(){
super.Show();
System.out.println("领带");
}
}
最后的测试类:
public class Text {
public static void main(String[] args) {
Person xc = new Person("小菜");
System.out.println("第一种装扮:");
WearSneakers pqx = new WearSneakers();
BigTrouser kk = new BigTrouser();
TShirts dtx = new TShirts();
pqx.Decorate(xc);
kk.Decorate(pqx);
dtx.Decorate(kk);
dtx.Show();
System.out.println();
System.out.println();
System.out.println("第二种装扮:");
WearSuit px = new WearSuit();
WearTie ld=new WearTie();
WearSuit xz=new WearSuit();
px.Decorate(xc);
ld.Decorate(px);
xz.Decorate(ld);
xz.Show();
}
}
最后的运行的代码:
第一种装扮:
装扮的小菜
破球鞋
垮裤
大T恤
第二种装扮:
装扮的小菜
西装
领带
西装
总结:
其实我们可以看出,这就是在利用多态进行对穿衣的控制,人类可以说是爷爷类,而服饰类是父类,其他的衣服就是子类,那么我们怎么实现对穿衣的控制呢?从第一种穿搭来看:我们创建人类的对象,将它包装在破球鞋中,将破球鞋包装在垮裤中,再将垮裤包装在大T恤中,最后调用大T恤中的show方法,因为代码执行顺序的原因,大T恤会先执行自己的输出语句,在去调用执行父类的方法,在通过多态的方式,将其他衣服类一一执行。就像递归一样层层调用执行。
定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
说明:
我在公司上班三年了,很是优秀,所以我想涨工资,顺便和经理说一下自己请假的事情,当你将情况告知经理时,经理却说道:请假可以批,但是涨薪资需要向上级报告。所以经理将这件事告诉了总监。总监却说这件事他没有权利,要经过总经理的批准才行。
根据这件事情,如果设计代码,我们应该怎么设计呢?
我们创建一个管理这类:
public abstract class Manager {
protected String name;
//设置管理者的上级
protected Manager superior;
public Manager(String name) {
this.name = name;
}
//设置管理者的上级
public void setSuperior(Manager superior) {
this.superior = superior;
}
abstract public void RequestApplication(Request request);
}
经理类
//经理
public class CommonManager extends Manager {
public CommonManager(String name) {
super(name);
}
@Override
public void RequestApplication(Request request) {
if(request.getRequestType().equals("请假") && request.getNumber() <=2){
System.out.println(request.getRequestContext()+" "+"数量"+request.getNumber()+"被批准!");
}else {
if (superior!=null){
superior.RequestApplication(request);
}
}
}
}
总监类
//总监
public class Majoedomo extends Manager {
public Majoedomo(String name) {
super(name);
}
@Override
public void RequestApplication(Request request) {
if(request.getRequestType().equals("请假") && request.getNumber() <=5){
System.out.println(request.getRequestContext()+" "+"数量"+request.getNumber()+"被批准!");
}else {
if (superior!=null){
superior.RequestApplication(request);
}
}
}
}
总经理类
//总经理
public class GeneralManager extends Manager {
public GeneralManager(String name) {
super(name);
}
@Override
public void RequestApplication(Request request) {
if(request.getRequestType().equals("请假")){
System.out.println(request.getRequestContext()+" "+"数量"+request.getNumber()+"被批准!");
}else if(request.getRequestType().equals("加薪") && request.getNumber() <=500) {
System.out.println(request.getRequestContext()+" "+"数量"+request.getNumber()+"被批准!");
} else if(request.getRequestType().equals("加薪") && request.getNumber() >500) {
System.out.println(request.getRequestContext()+" "+"数量"+request.getNumber()+"再说吧!");
}
}
}
请假类
public class Request {
private String requestType; //申请类别
private String requestContext; //申请内容
private int number; //数量
public Request() {
}
public Request(String requestType, String requestContext, int number) {
this.requestType = requestType;
this.requestContext = requestContext;
this.number = number;
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public String getRequestContext() {
return requestContext;
}
public void setRequestContext(String requestContext) {
this.requestContext = requestContext;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
测试类
public class Text {
public static void main(String[] args) {
CommonManager zhangsan=new CommonManager("张三");
Majoedomo lisi=new Majoedomo("李四");
GeneralManager wangwu=new GeneralManager("王五");
zhangsan.setSuperior(lisi);
lisi.setSuperior(wangwu);
Request request=new Request("请假","小菜请假",1);
zhangsan.RequestApplication(request);
Request request2=new Request("请假","小菜请假",4);
zhangsan.RequestApplication(request2);
Request request3=new Request("加薪","小菜请求加薪",500);
zhangsan.RequestApplication(request3);
Request request4=new Request("加薪","小菜请求加薪",1000);
zhangsan.RequestApplication(request4);
}
}
实现代码
小菜请假 数量1被批准!
小菜请假 数量4被批准!
小菜请求加薪 数量500被批准!
小菜请求加薪 数量1000再说吧!
总结:
我们从小菜第一个请假的实现代码来看,它是将总监的对象包裹在经理中,再将总经理包裹在总监中,这样就实现了,总经理在最里面,经理在最外面的情形。而小菜的请假类创建的对象,是被经理调用的。经理根据自己的权限,进行判断,如果权限不够那么再次通过多态的形式调用被经理包裹的总监的方法,总监再次进行判断。
从测试类的代码中,我们就可以看出。在职责链模式中,我们可以根据自己的需求来调整每个职务的上级。而客户端的代码中都是由“经理”发起的,但实际谁来具体管理类来处理,客户端是不知道的。
而装饰模式是为已有功能进行添加更多功能的一种方式。当我们需要新的衣服进行搭配时,装饰模式把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊的行为时,可以根据需要有选择的、按顺序的使用装饰功能包装对象。