装饰模式

         刚开始接触这个设计模式 感觉有点难懂,个人的学习办法是先拿着前辈的代码就行断点调试 然后再回头想想设计的初衷,

这样可能效果要更好  安利给刚学这个的童靴。

1. 装饰者模式 

      动态的给一个对象(需要装饰的对象)添加一些额外的职责,就增加功能而言,装饰模式比生成子类更为灵活 。、

      砸门看看对应的结构图

1.Component是定义对象职责的接口 可以给对象动态的增加职责

2.ConcreteCompoment 是具体的需要装饰对象

3.Decorator 是一个抽象类  它和 ConcreteCompoment都实现了Component接口  只不过Decorator可以更好的扩展对Component的修饰

4.ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰对象  里面的方法主要是对Component 需要装饰的target进行装饰

还是老模式 我们来一个简单的案例

假如小白今天要出去约会(第一次哦)那么怎么搭配自己的穿法

我们拿出简单粗暴的方式

package 装饰模式.Method3;

public class PersonMethod1 {
    private String name;

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

    public void WearTshirt() {
        System.out.println("穿一件黄色的Tshirt");
    }


    public void WearBigTrouser() {
        System.out.println("穿一件垮裤");
    }

    public void WearSnakers() {
        System.out.println("穿一双蛇皮鞋");
    }

    public void WearSuit() {
        System.out.println("穿一件西装");
    }

    public void WearTie() {
        System.out.println("打一下领带");
    }

    public void Wearshershoes() {
        System.out.println("穿一双布鞋");
    }


}

测试:

package 装饰模式.Method3;

import org.junit.Test;

public class test1 {

    @Test
    public void testMethod(){
        PersonMethod1 method1=new PersonMethod1("小明");
        System.out.println("第一种方式");
        method1.WearBigTrouser();
        method1.WearTie();
        method1.WearTshirt();



        System.out.println("第二种方式");
        method1.Wearshershoes();
        method1.WearSuit();
        method1.WearTshirt();
    }
}

看到上面这一坨 表面上是可以完成我所想要的需求 但是如果我要增加一个“超人”打扮 ,我们在PersonMethod1方法里面改改相应的方法吗?显然这违背了开放-封闭原则(面对新需求时候通过新加代码进行的   而不是更改现有的代码)

好了  我们看看装饰者的结构图将代码修改如下 

要点: 装饰者和被装饰者同时拥有同一个父类

父类:

package 装饰模式.Method3;

public interface Dress {

    public void dressWhat();
}

抽象装饰者:

package 装饰模式.Method3;

public abstract class Decorate  implements Dress{

    private Dress dress;

    public Decorate(Dress dress) {
        this.dress = dress;
    }

    @Override
    public void dressWhat() {
        dress.dressWhat();
    }
}

被装饰者:具体的装饰对象(要装饰者)

package 装饰模式.Method3;

public class Person implements Dress {

    private String name;

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

    @Override
    public void dressWhat() {

        System.out.println("出去约会该怎么穿呢");
    }
}

接下来3个就是我们怎么去装饰的具体实现(也可以是n个)

DressMatching1 具体装饰者1

package 装饰模式.Method3;

public class DressMatching1 extends Decorate {



    public DressMatching1(Dress dress) {
        super(dress);
    }

    @Override
    public void dressWhat() {
        super.dressWhat();
        System.out.println("穿一件垮裤");
    }
}

DressMatching2 具体装饰者2

package 装饰模式.Method3;

public class DressMatching2 extends Decorate {



    public DressMatching2(Dress dress) {
        super(dress);
    }

    @Override
    public void dressWhat() {
        super.dressWhat();
        System.out.println("穿一双蛇皮鞋");
    }
}

DressMatching3 具体装饰者3

package 装饰模式.Method3;

public class DressMatching3 extends Decorate {



    public DressMatching3(Dress dress) {
        super(dress);
    }

    @Override
    public void dressWhat() {
        super.dressWhat();
        System.out.println("穿一件西装");
    }
}

。。。。。我们还可以加很多具体装饰者

接下来我们测试一下

package 装饰模式.Method3;

import org.junit.Test;

public class test {
    @Test
    public void testDress() {
        Person person = new Person("小白");

        DressMatching3 dress3 = new DressMatching3(new DressMatching2(new DressMatching1(person)));

        dress3.dressWhat();


    }
}

通过结果我们可以看到 穿什么这个完全不是由person发起 而是由decorate主动去装饰person

关键点:
1、Decorate抽象类中,持有Dress接口,方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。
2、DressMatching1,DressMatching2,DressMatching3抽象类的子类(具体装饰者),里面都有一个构造方法调用super(dress),这一句就体现了抽象类依赖于子类实现即抽象依赖于实现的原则。因为构造里面参数都是Dress接口,只要是该Dress的实现类都可以传递进去,即表现出 DressMatching3 dress3 = new DressMatching3(new DressMatching2(new DressMatching1(person)));这种结构的样子。所以当调用 dress3.dressWhat();的时候,又因为每个具体装饰者类中,都先调用 super.dressWhat();方法,而该super已经由构造传递并指向了具体的某一个装饰者类(这个可以根据需要调换顺序),那么调用的即为装饰类的方法,然后才调用自身的装饰方法,即表现出一种装饰、链式的类似于过滤的行为。

 

  • 是不是特别不好理解呢?没关系 刚好中午没怎么吃 再来一个日常的例子 咋们来用一个例子写出一个陕北西饼的教程
  • 现在需要一份陕北西饼,主体是饼,可以选择添加油条、热狗、地沟油、正宗地沟油、辣皮子等等许多其他的配料,配料不同导致卖的价格也不同  这种情况下就可以使用装饰者模式

首先我们来一个西饼的父类 (带有名字和价格) 每一个具体类型的西饼价格不同

package 装饰模式.Method4;

public abstract class Cake {

    protected  String name ;

    public String getName(){
        return name;
    }

    public abstract double getPrice();
}

然后来一个装饰者 (也就是配菜 是一个抽象类)

package 装饰模式.Method4;

public abstract class CakeMaterials extends Cake {


    public abstract String getName();

}

接着就是具体的西饼对象

package 装饰模式.Method4;

public class ShanbeiCake extends Cake {


    public ShanbeiCake() {
        name="陕北西饼";
    }

    @Override
    public double getPrice() {
        return 5;
    }
}

接下来的几个类  就是不同的装饰者 也就是不同的配菜材料

HotDogMaterals 热狗              LettuceMaterals  蔬菜           SpicyMaterals  辣条         YoutiaoMaterials 油条 俺就写在一起了

package 装饰模式.Method4;

public class HotDogMaterals extends CakeMaterials {

    private Cake cake;

    public HotDogMaterals(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getName() {
        return cake.getName()+"热狗";
    }

    @Override
    public double getPrice() {
        return cake.getPrice()+5;
    }
}

package 装饰模式.Method4;

public class LettuceMaterals extends CakeMaterials {

    private Cake cake;

    public LettuceMaterals(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getName() {
        return cake.name+"生菜";
    }

    @Override
    public double getPrice() {
        return cake.getPrice()+2;
    }
}
package 装饰模式.Method4;

public class SpicyMaterals extends CakeMaterials {

    private Cake cake;

    public SpicyMaterals(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getName() {
        return cake.getName()+"辣条";
    }

    @Override
    public double getPrice() {
        return cake.getPrice()+3;
    }
}

package 装饰模式.Method4;

public class YoutiaoMaterials extends CakeMaterials {

    private  Cake cake;

    public YoutiaoMaterials(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getName() {
        return cake.getName()+"油条";
    }

    @Override
    public double getPrice() {
        return cake.getPrice()+3;
    }
}

咋现在就去买小小和wy的西饼

package 装饰模式.Method4;

import org.junit.Test;

public class TestCake {

    @Test
    public void buyCake(){
        //构建一个 小小的西饼
        Cake cake=new ShanbeiCake();
        //接下来开始装饰这个对象 老板加点辣条和热狗 多少钱
        SpicyMaterals spicyMaterals=new SpicyMaterals(cake);
        HotDogMaterals hotDogMaterals=new HotDogMaterals(spicyMaterals);
        //价格为
        System.out.println("小小的西饼价格为"+hotDogMaterals.getPrice());



        //构建一个wy西饼(油条加青菜+热狗)
        Cake cake1=new ShanbeiCake();
        //接下来开始装饰这个对象 老板加点油条青菜+热狗 多少钱
        HotDogMaterals hotDogMaterals1=new HotDogMaterals(new LettuceMaterals(new YoutiaoMaterials(cake1)));
        //价格为
        System.out.println("wy西饼价格为"+hotDogMaterals1.getPrice());


    }
}

结果:

到此为止 如果还是不是很明白 个人建议下次可以去买个西饼试试 哈哈哈。。。。

总结下:把类中的装饰功能从类中移除出去,这样可以简化原来的类 ,有效的把类的核心功能和原始功能区分开来 而且可以去除重复的装饰逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值