装饰模式,代理模式,继承

 

1:装饰模式举例:

定义一个接口Food:

public interface Food {

    // 打印出食材
    public void printIngredients();
}

简单的炒个米饭:

public class Rice implements Food{

    @Override
    public void printIngredients() {
        System.out.println("Rice");
    }
}

Test:

public static void main(String[] args) {
        Food rice = new Rice();
        rice.printIngredients();
    }

 

打印出:

Rice

 

这时候想加个蛋:

public class RiceFriedWithEgg implements Food{

    private Food food;

    public RiceFriedWithEgg(Food food) {
        this.food = food;
    }

    @Override
    public void printIngredients() {
        System.out.println("Egg");
        food.printIngredients();
    }
}

 

Test:

public static void main(String[] args) {
        Food rice = new Rice();
        rice = new RiceFriedWithEgg(rice);
        rice.printIngredients();
    }

 打印:

Egg
Rice

(1)RiceFriedWithEgg为装饰对象,Rice为被装饰对象。

(2)装饰对象RiceFriedWithEgg包含被装饰对象Rice的引用,装饰对象在被装饰对象执行之前或者之后添加附加功能,

(3)以上例子中,在打印Rice的前面,加上Egg。这样就确保了在炒饭Rice这个类不改变的情况下,加上Egg,生成蛋炒饭,以此达到添加功能的效果。

 

2:使用装饰模式相对于继承的好处:

举个例子,我们先定义一个Animal接口:

public interface Animal {

    public void action();
}

然后定义一只Pig实现该接口:

public class Pig implements Animal {
    @Override
    public void action() {
        System.out.println("pig eat");
    }
}

再定义一只Bird:

public class Bird implements Animal{

    @Override
    public void action() {
        System.out.println("bird eat");
    }
}

Test:

 public static void main(String[] args) {
        Animal pig = new Pig();
        pig.action();

        Animal bird = new Bird();
        bird.action();
    }

打印出:

pig eat
bird eat

现在有新的需求,要给Pig这个类加一个需求,eat之后run,给Bird这个类加一个需求,吃完之后fly,一般的做法是在Pig和Bird各自添加该功能:

Pig:

public class Pig implements Animal{

    @Override
    public void action() {
        System.out.println("pig eat");
run(); } public void run(){ System.out.println("pig run"); } }

Bird:

public class Bird implements Animal{

    @Override
    public void action() {
        System.out.println("bird eat");
     fly(); } public void fly(){ System.out.println("bird fly"); } }

 

打印出:

pig eat
pig run
bird eat
bird fly

现在只有两个动物Pig和Bird还好,如果还有Rabbit、Tiger、Fish等等,如果使用继承的话,会有很多组合,会比较麻烦,下面来看看装饰模式的做法:

Pig还是保持原来的不变:

public class Pig implements Animal{

    @Override
    public void action() {
        System.out.println("pig eat");
    }
}

给他添加一个Run的装饰:

public class Run implements Animal{
    Animal animal = null;

    public Run(Animal animal) {
        this.animal = animal;
    }

    @Override
    public void action() {
     animal.action(); System.out.println(
"run"); } }

 

Bird还是保持原来的:

public class Bird implements Animal{

    @Override
    public void action() {
        System.out.println("bird eat");
    }
}

给他加一个Fly的装饰:

public class Fly implements Animal{

    Animal animal = null;

    public Fly(Animal animal) {
        this.animal = animal;
    }

    @Override
    public void action() {
        animal.action();
        System.out.println("fly");
    }
}

Test:

public static void main(String[] args) {
        Animal pig = new Pig();
        pig = new Run(pig);
        pig.action();

        Animal bird = new Bird();
        bird = new Fly(bird);
        bird.action();

    }

打印出:

pig eat
run
bird eat
fly

可以看出,我们想要对Pig和Bird增加新功能,但是并没有直接在这两个类上面修改,而是另外设置一个装饰类,想要哪个功能,客户端就直接调用这个装饰类,并且持有原来类的引用。

而且装饰可以层层嵌套,比如上面的,目前Pig的action包括eat和run,如果我想让他也有fly的功能,可以这样做:

public static void main(String[] args) {
        Animal pig = new Pig();
        pig = new Run(pig);
        pig = new Fly(pig);
        pig.action();
    }

结果:

pig eat
run
fly

首先是new Pig,是一只pig,想要让他有Run的功能,就new 一个Run的装饰类,并持有pig的引用。再想让他有Fly的功能,就new一个Fly装饰类,并持有pig的引用。

这个过程充分体现了装饰模式的灵活性,并且我们不需要去改变原来的Pig类就能够达到增加功能的效果。

这时候如果来的新需求是增加Tiger、Rabbit等,我们就按照Pig和Bird的方式增加新的类,如果是要给各种动物增加新的功能,比如Tiger要加Run和Breath,我们看前面已经有了Run的装饰类,

就只需要增加一个Breath的装饰类,然后用Run和Breath来装饰Tiger。Rabbit的需求是Run和Eat,那就不需要增加任何装饰类,直接用现成的就行。

 经典用例:JAVA IO

https://www.cnblogs.com/wnpp/p/17032121.html

类似的设计思想:AOP

3:装饰模式的缺点:

每个特点都需要设计成一个装饰类,会有比较多的类产生

 

4:和代理模式(静态代理)的区别:

举个买房子的例子:

定义一个接口:

public interface Consumer {
    public void buyHouse();
}

一个叫Jack的人要买房子:

public class Jack implements Consumer{

    @Override
    public void buyHouse() {
        System.out.println("buy house");
    }
}

但是肯定是要找中介帮忙,中介Agency在帮Jack买房子的时候忙前忙后的做了很多事情:

public class Agnecy implements Consumer{

    private Consumer consumer;

    public Agnecy() {
        this.consumer = new Jack();
    }

    @Override
    public void buyHouse() {
        System.out.println("do many task....");
        consumer.buyHouse();
        System.out.println("do many task again....");
    }
}

 

Test:

 public static void main(String[] args) {
        Consumer consumer = new Agnecy();
        consumer.buyHouse();
    }

结果:

do many task....
buy house
do many task again....

现在来说说代理模式和装饰模式的区别:

1)先从客户端调用的角度来看看区别:对于客户端来说,他们的真实类分别是Jack和Pig,但是Jack对于客户端是隐藏的,创建该对象的实例是在代理类Agency。

而对于装饰模式,真实类Pig是客户端定义的,他作为参数传递给装饰类的构造器。

即代理模式,类的关系客户端不需要去关注,只要使用代理类就可以,而装饰模式,类的各种组合,需要客户端自己去制定。

代理模式:

public static void main(String[] args) {
        Consumer consumer = new Agnecy();
        consumer.buyHouse();
    }

装饰模式:

public static void main(String[] args) {
        Animal pig = new Pig();
        pig = new Run(pig);
        pig = new Fly(pig);
        pig.action();
    }

 

posted @ 2021-09-15 08:44  蜗牛攀爬  阅读(77)  评论(0编辑  收藏  举报