装饰模式,代理模式,继承
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(); }