【设计模式】 装饰模式
系列文章目录
文章目录
- 系列文章目录
- 服饰系统第一版
- 服饰系统第二版
- 装饰模式
- 服饰代码第三版
- 装饰模式总结
- 总结
服饰系统第一版
在介绍装饰模式这一设计模式时,我们会通过一个简单的穿衣系统来介绍,如果我们先不谈模式,我们要怎么开发这个系统?
第一版代码:
public class Person{private String name;public Person(String name){this.name = name;}public void wearTShirts(){System.out.println("大T恤");}public void wearBigTrouser() {System.out.println("垮裤");}public void wearSneakers(){System.out.println("球鞋");}public void wearSuit(){System.out.println("西装");}public void wearTie(){System.out.println("领带");}public void wearLeatherShoes(){System.out.println("皮鞋");}public void show(){System.out.println("装扮的" + name);}public void main(String[] args) {Person p = new Person("张三");System.out.println("第一种穿搭");p.wearTShirts();p.wearBigTrouser();p.wearSneakers();p.show();System.out.println("第二种穿搭");p.wearSuit();p.wearTie();p.wearLeatherShoes();p.show();}}
控制台输出
第一种装扮:
大T恤 垮裤 球鞋装扮的张三
第二种装扮:
西装 领带、皮鞋装扮的张三
就目前来看,功能是实现了,但是如果我需要增加“超人”的装扮,我们要如何做呢,这里我们只能修改Person类,但是这违背了开放-封闭原则了。 于是我们尝试通过把这些服饰写成子类来避免违背开放-封闭原则。
服饰系统第二版
代码示例:
//Person类public class Person{private String name;public Person(String name){this.name = name;}public void show(){System.out.println("装扮的" + name);}}//服饰抽象类public abstract class Finery{public abstract void show();}//各种服饰子类public class TShirts extends Finery{@Overridepublic void show() {System.out.println("大T恤");}}public class BigTrouser extends Finery{@Overridepublic void show() {System.out.println("垮裤");}}public class Sneakers extends Finery{@Overridepublic void show() {System.out.println("球鞋");}}public class Suit extends Finery{@Overridepublic void show() {System.out.println("西装");}}public class Tie extends Finery{@Overridepublic void show() {System.out.println("领带");}}public class LeatherShoes extends Finery{@Overridepublic void show() {System.out.println("皮鞋");}}public void main(String[] args) {Person xc = new Person("张三");System.out.println("第一种装扮");Finery dtx = new TShirts();Finery kk = new BigTrouser();Finery pqx = new Sneakers();dtx.show();kk.show();pqx.show();xc.show();System.out.println("第二种装扮");Finery xz = new Suit();Finery ld = new Tie();Finery px =new LeatherShoes();xz.show();ld.show();px.show();xc.show();}
}
这里结果显示与前例相同
这下看着像是已经面向对象了,如果需要增加超人装扮,那么只需要增加子类就可以了,但是,这里我们虽然通过抽象和继承将“服饰类”与“人”类分离了,但是还是有其他的问题。
我们仔细看这段代码
dtx.show();kk.show();pqx.show();xc.show();
我们在这段代码里,把“大T恤”、“垮裤”、“球鞋”、“装扮的张三”一个词一个词的显示出来,这就好似我们当着大家所有人的面,先穿上T恤,再穿裤子,在穿鞋,这肯定是不合理的,一方面我们的穿衣顺序是有讲究的,另一方面,我们的服饰组合是不稳定的,也就是说,我们在这里需要把所需的功能按照正确的顺序串联起来进行控制
装饰模式
装饰模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成四类更为灵活。
下面我们看基本代码实现:
//Component类abstract class Component{public abstract void Operation();}//ConcreteComponent类class ConcreteComponent extends Component{@Overridepublic void Operation() {System.out.println("具体对象的实际操作");}}//Decorator类abstract class Decorator extends Component{protected Component component;//装饰一个Component对象public void setComponent(Component component){this.component = component;}//重写Operation(),实际调用component的Operation方法public void Operation(){if(component != null){component.Operation();}}}//ConcreteDecoratorA类class ConcreteDecoratorA extends Decorator{private String addedState; //本类独有字段public void Operation(){super.Operation(); //首先运行了原有Component的Operation()this.addedState = "具体装饰对象A的独有操作"; //再执行本类独有功能System.out.println(this.addedState);}}class ConcreteDecoratorB extends Decorator{//本类独有方法,以区别于ConcreteDecorateA类private void AddedBehavior(){System.out.println("具体装饰对象B的独有操作");}public void Operation(){super.Operation(); //首先运行了原有Component的Operation()this.AddedBehavior(); //再执行本类独有功能}}public void main(String[] args) {ConcreteComponent c = new ConcreteComponent();ConcreteDecoratorA d1 = new ConcreteDecoratorA();ConcreteDecoratorB d2 = new ConcreteDecoratorB();d1.setComponent(c); // 先用d1来包装cd2.setComponent(d1); // 再用d2来包装d1d2.Operation(); // 最终执行d2的Operation();}}
在上述代码中:
Component是定义一个对象接口,可以给这些对象动态的添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无须知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
装饰模式是利用SetComponent来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
下面,我们将对上面的服饰系统代码,用装饰模式改写。
服饰代码第三版
public interface ICharacter{public void show();}public class Person implements ICharacter{private String name;public Person(String name){this.name = name;}public void show(){System.out.println("装扮的" + name);}}public class Finery implements ICharacter{protected ICharacter component;public void decorate(ICharacter component){this.component = component;}@Overridepublic void show() {if(this.component != null){this.component.show();}}}//具体服饰类public class TShirts extends Finery{public void show(){System.out.println("大T恤");super.show();}}public class Tie extends Finery{public void show(){System.out.println("领带");super.show();}}public class Sneakers extends Finery{public void show(){System.out.println("球鞋");super.show();}}public void main(String[] args) {Person xc = new Person("张三");System.out.println("第一种装扮 : ");Tie pqx = new Tie();pqx.decorate(xc);TShirts kk = new TShirts();kk.decorate(pqx);Sneakers qq = new Sneakers();qq.decorate(kk);qq.show();}
此时如果我们需要增加一个草帽装扮,那么我们就只需要增加草帽类,再修改下装饰方案就好了。
装饰模式总结
装饰模式是为一有功能动态的添加更多功能的一种方式 ,我们到底在什么时候用它呢?当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为, 这种做法的问题主要在于,它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,就像我们起初的那个‘人’类,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。 而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能,放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择的,按顺序的使用装饰功能包装对象了。 装饰模式的优点是: 把类中的装饰功能从类中搬移去除,这样可以简化原有的类。 这样做的做大好处就是 有效的把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。 但是我们需要注意 装饰模式的装饰顺序很重要 ,最理想的情况是,保证装饰类之间彼此独立,这样它们就可以以任意的顺序进行组合了!
总结
以上就是本文全部内容,本文主要向大家介绍了设计模式中的装饰模式,通过一个服饰系统引入代码模版,并将原系统用装饰代码模式进行改造。感谢各位能够看到最后,如有问题,欢迎各位大佬在评论区指正,希望大家可以有所收获!创作不易,希望大家多多支持!
最后,大家再见!祝好!我们下期见!