大话设计模式读书笔记(装饰模式)

人物:大鸟,小菜

事件:小菜要去约会,不知道穿什么,怎么搭配,大鸟借着搭配衣服这件事,给小菜讲了装饰模式


装饰模式:

1.大鸟让小菜通过代码实现装扮,大鸟指出了小菜的不足

2.在结合了开放封闭原则后,小菜进行了第二次装扮,大鸟依然指出了小菜的正确和失误,引出了装饰模式

3.小菜在领悟了装饰模式后,进行了第三次装扮

4.最后对装扮模式进行了小结

小菜的第一次装扮

@Slf4j
public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void wearTShirts() {
        log.info("大T恤");
    }、

    public void wearBigTrouser() {
        log.info("垮裤");
    }

    public void wearSneakers() {
        log.info("破球鞋");
    }

    public void wearSuit() {
        log.info("穿西装");
    }

    public void wearTie() {
        log.info("领带");
    }

    public void wearLeatherShoes() {
        log.info("皮鞋");
    }

    public void show() {
        log.info("装扮的:{}", name);
    }
}

客户端:

@Slf4j
public class PersonWear {
    public static void main(String[] args) {
        Person xc = new Person("小菜");
        log.info("第一种装扮:");
        xc.wearSuit();
        xc.wearTie();
        xc.wearLeatherShoes();
        xc.show();
    }
}

大鸟:现在需要增加超人的装扮,需要怎么改呢?

小菜的第二次装扮

在学习了开放-封闭原则后,小菜出了第二次装扮

 Person类:

@Slf4j
public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void show() {
        log.info("装扮的:{}", name);
    }
}

服饰抽象类:

public abstract class Finery {
    public abstract void show();
}

各种服饰子类:

@Slf4j
public class TShirts extends Finery {
    @Override
    public void show() {
        log.info("大T恤");
    }
}
@Slf4j
public class BigTrouser extends Finery {
    @Override
    public void show() {
        log.info("垮裤");
    }
}
@Slf4j
public class Sneakers extends Finery {
    @Override
    public void show() {
        log.info("破球鞋");
    }
}

......

客户端代码:

@Slf4j
public class PersonWear {
    public static void main(String[] args) {
        Person xc = new Person("小菜");
        log.info("第一种装扮:");
        Finery dtx = new TShirts();
        Finery kk = new BigTrouser();
        Finery pqx = new Sneakers();

        dtx.show();
        kk.show();
        pqx.show();
        xc.show();
    }
}

小菜:这下结果和之前的一样,而且面向了对象,只要有新的服饰,再增减子类即可

大鸟:但是这段代码还是有点问题:

dtx.show();
kk.show();
pqx.show();
xc.show();

这里显式地放在了外面,这就好比当着大家的面在穿衣服,其实应该在内部组装,我们要把所需的功能按正确的顺序串联起来进行控制,于是这里就引入了新的模式--装饰模式

装饰模式

装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。

它的实现:

Component类,这是最原始的对象,是一个对象接口,可以给对象动态添加职责

public abstract class Component {
    public abstract void Operation();
}

ConcreteComponent类,定义一个具体的对象,是最基本接口的实现,我们要装饰它

@Slf4j
public class ConcreteComponent extends Component {
    @Override
    public void Operation() {
        log.info("具体对象的操作");
    }
}

Decorator类,装饰抽象类,继承了Component,从外类扩展Component功能

public class Decorator extends Component {
    protected Component component;

    public void setComponent(Component component) {
        this.component = component;
    }

    @Override
    public void Operation() {
        if (component != null) {
            component.Operation();
        }
    }
}

ConcerteDecoratorA类和ConcerteDecoratorB类,先执行Operation()方法,再执行addedState赋值或addedBehavior方法调用,相当于进行了装饰

@Slf4j
public class ConcerteDecoratorA extends Decorator {
    private String addedState;

    @Override
    public void Operation(){
        this.Operation();
        addedState = "New State";
        log.info("具体装饰对象A的操作");
    }
}
@Slf4j
public class ConcreteDecoratorB extends Decorator {

    @Override
    public void Operation() {
        this.Operation();
        AddedBehavior();
        log.info("具体装饰对象B的操作");
    }

    private void AddedBehavior() {
        //本类独有的方法,以作区别
    }
}

客户端代码,先实例化对象c,再用ConcerteDecoratorA的实例化对象d1来包装c,再用ConcreteDecoratorB实例话的对象d2包装d1,最终再执行d2的Operation()

public static void main(String[] args) {
    ConcreteComponent c = new ConcreteComponent();
    ConcreteDecoratorA d1 = new ConcreteDecoratorA();
    ConcreteDecoratorB d2 = new ConcreteDecoratorB();

    d1.setComponent(c);
    d2.setComponent(d1);
    d2.Operation();
}

小菜:原来装饰模式是利用setComponent来对对象进行包装,这样每个装饰对象的实现就和如何使用这个对象分开了,每个装饰对象只用关心自己的功能

大鸟:那我们刚刚用的Person()类,是属于Component类还是ConcreteComponent类呢?

小菜:我觉得如果只有ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类,同理,如果没有ConcreteDecoratorA和ConcreteDecoratorB,而是只有一个ConcreteDecorator类,那么ConcreteDecorator类和Decorator类也可以合二为一,这里我们就不必用Component类,直接让服饰类Decorator类继承人类ConcreteComponent即可。

小菜的第三次装扮

Person类(ConcreteComponent类)

@Slf4j
public class Person {
public Person() {}

private String name;

public Person(String name) {
this.name = name;
}

public void show() {
log.info("装扮的:{}", name);
}
}

服饰类(Decorator)

public class Finery extends Person {
protected Person component;

public void Decorate(Person component) {
this.component = component;
}

@Override
public void show() {
if (component != null) {
component.show();
}
}
}

具体服饰类:

@Slf4j
public class TShirts extends Finery {
    @Override
    public void show() {
super.show(); log.info(
"大T恤"); } } @Slf4j public class Sneakers extends Finery { @Override public void show() {
super.show(); log.info(
"破球鞋"); } } @Slf4j public class BigTrouser extends Finery { @Override public void show() {
super.show(); log.info(
"垮裤"); } }

小结

1.装饰模式:

装饰模式是为已有功能动态地添加更多功能的一种方式

2.什么时候用装饰模式?

在最初设计系统时,当系统需要新的功能,就要向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责和主要行为,它们在主类添加了新的字段,新的逻辑,增加了主类的复杂度,而新加入的东西可能只是为了满足某个特殊的需求。而装饰模式把要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此要执行特殊行为时,客户代码就可以在运行时有选择地,按顺序地使用装饰功能包装对象了

 3.优点:

    (1)把类中的装饰功能从类中搬移去除,这样可以简化原有的类

    (2)有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑

原文地址:https://www.cnblogs.com/wencheng9012/p/13373994.html