装饰者模式
引入:
装饰者模式,从字面上一看就能很容易联想到这是用来装饰扩展一个类的,可以使扩展一个类具有某些属性和功能(方法),
那么,就有人会说了,扩展一个类,我在写一个子类继承于它,然后在扩展对应的属性或者功能不就行了,为什么要用装饰者模式呢?难道他有什么独特的地方吗?
带着这个疑问,接下来就让我们去看看装饰者模式到底是怎样一回事呢?
现在我们有一场戏需要拍一下,在一个浪漫的咖啡厅里,我们的女主人公和男主人公出现了(烂大街的剧情),接下来会有什么故事呢?别急,我们得用程序猿一族的交流方式来表达它:
我们来看下代码的实现:
下面是一场一镜:
//首先定义了一个抽象的Person类,男主和女主都该类的具体实现
public abstract class Person {
abstract void look();
}
//女主
public class Girl extends Person{
@Override
void look() {
//nothing to do
}
}
//男主
public class Lad extends Person{
@Override
void look() {
//nothing to do
}
}
//两人就这样见面了,没有任何打扮,都略显邋遢,那么,接下来还会有故事吗? maybe not
public class CoffeeHouse {
private Girl mGirl;
private Lad mLad;
public CoffeeHouse() {
mGirl = new Girl();
mLad = new Lad();
mGirl.look();
mLad.look();
}
}
也许都应该稍微打扮一下,毕竟第一眼的印象还是很重要的。那么将如何做呢?通常我们在通过一个继承Girl、Lad的子类,
重写父类的look()方法就可以了,让我们来看一下如何实现?
一场二镜:
在一镜的基础上我们做一点小的修改,如下:
//装扮后的女主
public class BeautifulGirl extends Girl{
@Override
void look() {
//装扮一番
dressUp();
makeUp();
hairUp();
super.look();
}
private void dressUp() {
//选一套漂亮的衣服
System.out.println("白色连衣裙");
}
private void makeUp() {
System.out.println("化一个淡妆");
}
private void hairUp() {
System.out.println("长发披肩,空气刘海");
}
}
//男主也可以简单打扮一番
public class Gentleman extends Lad {
@Override
void look() {
dressUp();
hairUp();
super.look();
}
private void dressUp() {
System.out.println("一身帅气的西装");
}
private void hairUp() {
System.out.println("最帅的发型");
}
}
//咖啡屋里出现的是精心打扮的男主和女主了
public class CoffeeHouse {
private Girl mGirl;
private Lad mLad;
public CoffeeHouse() {
mGirl = new BeautifulGirl();
mLad = new Gentleman();
mGirl.look();
mLad.look();
}
}
//看看是不是和之前不一样了呢
public class Client {
public static void main(String args[]) {
CoffeeHouse coffeeHouse = new CoffeeHouse();
}
}
如上展示的,我们通过继承的方式,对起初的男主和女主两个类做了扩充,是的我们已经完成了类的扩充,但是还没有谈到装饰者模式,既然我们都实现需求了,还有用装饰者的必要吗?别急我们接着往下看。
如果在上面的基础上,突然我们的编剧说,女主还得染个指甲,男主再带块名贵的手表,又或者说我们的女主很任性打扮的顺序得调整一下。
这个时候怎么办呢?有人会说了,这个好办啊,把Gentleman、BeautifulGirl类按要求修改一下不就完了么。是的,但是如果剧本不停的改来改去,不停的变,你还愿意不断的去修改吗?你们确定你的修改不会引出什么未知的问题吗。
这种做法并不符合开闭原则(对扩展开发,对修改关闭,变化用扩展来实现,而不是去修改已有的代码)。那要如何做呢?我们接着往下走。
一场三镜:
我们把之前的方式pass掉,重新做一下调整:
在该场景下,我们不在通过继承去Girl、Lad类实现去他们的扩展,而是引入了一个新的抽象类Conmetician(化妆师),
Conmetician类的构造方法传入了一个参数Person类,可见应该是对传入的Person对象做相关的操作。而不同的扩展可以通过不同的Conmetician实现类来完成,不需要去修改类Girl和Lad。具体看如下代码部分:
//和之前一致,最初的三个类
public abstract class Person {
abstract void look();
}
public class Girl extends Person{
@Override
void look() {
}
}
public class Lad extends Person{
@Override
void look() {
}
}
//新增的抽象化妆师类
public abstract class Cosmetician extends Person{
private Person mSomeone;
public Cosmetician(Person someOne) {
this.mSomeone = someOne;
}
@Override
void look() {
this.mSomeone.look();
}
}
//如下三个类分别继承于Cosmetician,同时扩展完成了各自需要处理的工作
public class ClothCosmetician extends Cosmetician{
public ClothCosmetician(Person someOne) {
super(someOne);
}
@Override
void look() {
dressUp();
super.look();
}
private void dressUp() {
System.out.println("盛装打扮");
}
}
public class HairCosmetician extends Cosmetician{
public HairCosmetician(Person someOne) {
super(someOne);
}
@Override
void look() {
hairUp();
super.look();
}
private void hairUp() {
System.out.println("发型打扮");
}
}
public class FaceCosmetician extends Cosmetician{
public FaceCosmetician(Person someOne) {
super(someOne);
}
@Override
void look() {
faceUp();
super.look();
}
private void faceUp() {
System.out.println("面部打扮");
}
}
//现在需要布置一下开拍的准备工作,看看如何布置的
public class CoffeeHouse {
private Girl mGirl;
private Lad mLad;
public CoffeeHouse() {
/*这里我们对Girl进行了装扮,现在能清晰的看到,如果我们想添加新的扩展就不在需要去
* 修改对应的对象类,只需要在实现一个Cosmetician具体的功能类就能完成扩展,
* 可以看到,如果要调整扩展的顺序也是很方便的,只需修改对应的场景类,是不是更加易于扩展了?符合开闭原则
*/
mGirl = new Girl();
mLad = new Lad();
HairCosmetician hairCosmetician = new HairCosmetician(mGirl);
ClothCosmetician clothCosmetician = new ClothCosmetician(mGirl);
FaceCosmetician faceCosmetician = new FaceCosmetician(mGirl);
mGirl.look();
mLad.look();
}
}
到这里,装饰者模式的实现就完成了,怎么样?很简单吧!下面我们在来回顾一下,做个总结吧
装饰者模式:动态的给一个对象添加额外的指责,相对于生成子类的继承方式更加的灵活,易于扩展.
如下是对应的UML图:
Component(零件):抽象类或者接口,原始的核心对象
ConcreteComponent:具体构件(被装饰的对象)
Decorator:装饰角色:一般为抽象类,内部必须有一个private的Component变量,这是它需要装饰的对象.
下面简单总结下代码的实现过程:
public abstract class Component {
abstract void operation();
}
public abstract class Decorator extends Component {
private Component mComponent;
public Decorator(Component component) {
this.mComponent = component;
}
@Override
void operation() {
mComponent.operation();
}
}
public class ConcreteComponent extends Component {
@Override
void operation() {
//原始的基本的一些操作
}
}
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
void operation() {
extendOperation();
super.operation();
}
private void extendOperation() {
//装饰类需要完成的扩展工作
}
}
public class Client{
public static void main(String[] args) {
Component component = new ConcreteComponent();
component = new ConcreteDecorator(component);
component.operation();
}
}
继承---->静态增加类的功能
装饰---->动态增加类的功能
优点:
装饰者与被装饰者相互独立,无依赖,易于扩展.
继承关系的一种替代方案.
可以实现动态扩展实现类的功能.
缺点:多层的装饰是很复杂的,应避免过多的装饰类,想象一下,你收到一个礼物,拆开盒子里面还是盒子…你会有何感受
使用场景:
需要给一个类动态的增加,撤销功能.
为一批兄弟类改装或加装功能.