我比较喜欢吃红烧牛肉面,因为牛肉味道鲜美,能长肌肉,不发胖,尤其我们这里的杨记拉面更是一绝。没有吃过的同学们可以来我大河南尝一尝~哈哈不是打广告哈,是真的好吃~呦呵,服务员立马给我端上一碗拉面:
public class Noodles {
public void show() {
System.out.println("红烧牛肉面");
}
}
嗯,突然觉得仅吃牛肉面我觉得还不够,想在面里加个鸡蛋怎么办?这不简单吗?我继承面条类,扩展出一个加鸡蛋的子类不就行了?!
public class EggNoodles extends Noodles {
@Override
public void show() {
System.out.println("加了鸡蛋");
super.show();
}
}
身边的孩子看到我加了鸡蛋,他也想加点什么。“爸爸,我想加块卤豆腐干!”“好嘞,服务员给小孩的这碗加个豆干~”
public class TofuNoodles extends Noodles {
@Override
public void show() {
System.out.println("加了豆腐干");
super.show();
}
}
媳妇一看,“你们都加东西了,不行我也要加,我要面里加鸡蛋和豆干!”
public class EggTofuNooles extends Noodles {
@Override
public void show() {
System.out.println("加了鸡蛋和豆腐干");
super.show();
}
}
至此,我们一家三口吃的津津有味~
public class Main {
public static void main(String[] args) {
EggNoodles eggNoodles = new EggNoodles();
eggNoodles.show();
TofuNoodles tofuNoodles = new TofuNoodles();
tofuNoodles.show();
EggTofuNooles eggTofuNooles = new EggTofuNooles();
eggTofuNooles.show();
}
}
人饿的时候满脑子都是吃的,吃饱了之后大脑就有精神了,我越想越不对。这面里如果同时加了鸡蛋和豆腐干就要扩展一个子类出来,那如果有的人单独加香菜和加香菜,鸡蛋,豆腐干和加香菜,鸡蛋。。。。这组合起来可多的去了,类就要爆炸了呀!而且我们的设计违反了开闭原则,虽然通过继承实现了对扩展开放,但是我们对父类就是面条类覆写了show方法,即对修改开放了。而且我们的面条不应该设计为具体的类,应该是抽象或者接口,以便日后可以扩展出其他面出来。重新梳理之后,发现装饰器模式非常适合这样的场景,我们就来改造下。
首先建立面条接口(组件接口)以及其实现类(具体组件)
public interface Noodles {
void show();
}
public class BeefNoodles implements Noodles {
@Override
public void show() {
System.out.println("红烧牛肉面");
}
}
我们把面条抽象成接口,这样的话以后什么面条都不怕了,饸烙面,烩面,山西刀削面。。。
建立抽象装饰者(实现组件接口)以及其不同的实现类
public abstract class AbstractDecorator implements Noodles {
protected Noodles noodles;
public AbstractDecorator(Noodles noodles) {
this.noodles = noodles;
}
}
public class EggDecorator extends AbstractDecorator {
public EggDecorator(Noodles noodles) {
super(noodles);
}
@Override
public void show() {
System.out.println("加了鸡蛋");
this.noodles.show();
}
}
public class TofuDecorator extends AbstractDecorator {
public TofuDecorator(Noodles noodles) {
super(noodles);
}
@Override
public void show() {
System.out.println("加了豆腐干");
this.noodles.show();
}
}
到这里你会问,那加豆腐干和鸡蛋的怎么办?也建个对应的装饰类?根本没必要,就一句话搞定,直接省了一个类。我们来看客户端代码:
public class Main {
public static void main(String[] args) {
Noodles noodles = new BeefNoodles();
AbstractDecorator eggDecorator = new EggDecorator(noodles);
eggDecorator.show();
AbstractDecorator tofuDecorator = new TofuDecorator(noodles);
tofuDecorator.show();
AbstractDecorator egg_tofuDecorator = new EggDecorator(tofuDecorator);
egg_tofuDecorator.show();
}
}
先用TofuDecorator装饰,然后再用EggDecorator装饰就完了~是不是省个类?那我再加个香菜无非就是再用香菜的装饰一下而已。
Java,C++等语言有抽象类,这样我们就可以方便的把构造函数和Noodles接口成员变量提前写好了。像GO语言就没有抽象类,只能用接口了。
总结:
装饰器模式解决了类爆炸的问题,它对比直接继承符合了开闭原则,因为它没有修改父类的方法。而它是解决的扩展问题,核心功能保持不变,符合单一原则,即红烧牛肉面就是红烧牛肉面,无论加了多少配菜,核心是拉面。在真实的应用场景中,中间件技术很多都是用了装饰器模式,还有JDK的InputStream体系也是使用了该模式。如果说,要扩展的功能非常多,那么这样的情况应该去思考是不是自己设计的类出现了问题,而不是直接使用该模式了,所以具体的情况要具体分析。
最后给出GOF对装饰器模式的定义:允许向一个现有的对象添加新的功能,同时又不改变其结构。
1180

被折叠的 条评论
为什么被折叠?



