引言
相信大家都在外面吃过烤鱼,我们吃烤鱼的时候是不是都会点一些配菜放到烤鱼里面一起加热煮熟着吃,那么这些配菜肯定是根据个人的爱好添加的,有的人喜欢海带、金针菇、有的人喜欢粉丝、青菜等等,这些配菜的价格肯定是不一样的。不管加入什么配菜,最后的价格都是烤鱼的价格+配菜的价格,烤鱼分为黑鱼、草鱼、鲇鱼。那么我们如何来计算最终烤鱼+配菜的价格呢?
方法一:继承
这里我就只画出uml图了(仅仅是一部分) ,代码就不写了,缺点大家肯定一目了然。
通过继承关系导致类的关系之间非常臃肿,如果有很多的配菜的话,基本上会导致类的数量过多,并且之间的关系错综复杂,显然通过继承关系实现上述的方法不合理。那用什么方法来实现呢?装饰者设计模式这个时候应该上场了。
方法二:装饰者设计模式
一、定义
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。平时用到的IO里面的类、mybatis中的缓存组件等,如:BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(“c://a.txt”)));
二、uml图
组件(Component):组件接口定义了全部组件类和装饰器实现的行为;
组件实现类(ConcreteComponent):实现Component接口,组件实现类就是被装饰器装饰的原始对象,新功能或者附加功能都是通过装饰器添加到该类的对象上的
装饰器抽象类(Decorator):实现Component接口的抽象类,在其中封装了一个Component 对象,也就是被装饰的对象
具体装饰器类(ConcreteDecorator):该实现类要向被装饰的对象添加某些功能
三、装饰者模式的优点
相对于继承,装饰器模式灵活性更强,扩展性更强
灵活性:装饰器模式将功能切分成一个个独立的装饰器,在运行期可以根据需要动态的添加功能,甚至对添加的新功能进行自由的组合
扩展性:当有新功能要添加的时候,只需要添加新的装饰器实现类,然后通过组合方式添加这个新装饰器,无需修改已有代码,符合开闭原则
四、代码实现
上面说到了装饰者的设计模式的优点,那我们如何来体现呢?我们接着看刚才的例子使用装饰者模式如何实现。先看如下UML
这个时候代码怎么设计呢,请看代码:
Fish.java(通用接口,相当于uml中的Component)
package decorator;
public interface Fish {
double calculatePrice();
}
BlackFish .java(组件实现类)
package decorator;
public class BlackFish implements Fish{
@Override
public double calculatePrice() {
// TODO Auto-generated method stub
return 100;
}
}
GrassFish .java(组件的实现类)
package decorator;
public class GrassFish implements Fish {
@Override
public double calculatePrice() {
// TODO Auto-generated method stub
return 80;
}
}
CatFish .java(组件的实现类)
package decorator;
public class CatFish implements Fish {
@Override
public double calculatePrice() {
// TODO Auto-generated method stub
return 90;
}
}
DecoratorFish .java(装饰类,没有将他设置成抽象的)
package decorator;
public class DecoratorFish implements Fish {
private Fish fish;
public DecoratorFish(Fish fish) {
// TODO Auto-generated constructor stub
this.fish = fish;
}
@Override
public double calculatePrice() {
// TODO Auto-generated method stub
return fish.calculatePrice();
}
}
GreensDecoratorFish .java(具体装饰类)
package decorator;
/**
* @author hongtaolong
* 青菜烤鱼的装饰类
*/
public class GreensDecoratorFish extends DecoratorFish {
private Fish fish;//待装饰的fish
private double greensPrice = 5;//青菜5元
public GreensDecoratorFish(Fish fish) {
super(fish);
this.fish = fish;
// TODO Auto-generated constructor stub
}
@Override
public double calculatePrice() {
// TODO Auto-generated method stub
return greensPrice+fish.calculatePrice();
}
}
KelpDecoratorFish .java(具体装饰类)
package decorator;
/**
* @author hongtaolong
*
* 海带烤鱼的装饰类
*/
public class KelpDecoratorFish extends DecoratorFish {
private Fish fish;//待装饰的fish
private double kelpPrice = 8;//海带8元
public KelpDecoratorFish(Fish fish) {
super(fish);
// TODO Auto-generated constructor stub
this.fish = fish;
}
@Override
public double calculatePrice() {
// TODO Auto-generated method stub
return kelpPrice+fish.calculatePrice();
}
}
DecoratorTest .java(测试类)
package decorator;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
public class DecoratorTest {
public static void main(String[] args) throws FileNotFoundException {
//烤黑鱼
Fish blackFish = new BlackFish();
System.out.println("烤黑鱼的价格:"+blackFish.calculatePrice());
//烤草鱼
Fish grassFish = new GrassFish();
System.out.println("烤草鱼的价格:"+grassFish.calculatePrice());
//烤鲶鱼
Fish catFish = new CatFish();
System.out.println("烤鲶鱼的价格:"+catFish.calculatePrice());
//下面开始装饰了
//1,烤黑鱼里面加青菜,直接把待装饰的黑鱼传进去就行
GreensDecoratorFish greensDecoratorFish = new GreensDecoratorFish(blackFish);
System.out.println("烤黑鱼加青草的价格:"+greensDecoratorFish.calculatePrice());
//2,烤黑鱼里面加海带
KelpDecoratorFish kelpDecoratorFish = new KelpDecoratorFish(blackFish);
System.out.println("烤黑鱼里面加海带的价格:"+kelpDecoratorFish.calculatePrice());
//3,烤黑鱼里面既加青菜又加海带,这个时候把加青菜的烤黑鱼当作被装饰的对象就行
KelpDecoratorFish kelpDecoratorFish2 = new KelpDecoratorFish(greensDecoratorFish);
System.out.println("烤黑鱼加青菜加海带的价格:"+kelpDecoratorFish2.calculatePrice());
//4,将上面3写道一行代码里面如下,然后和下面的io操作的代码对比一下
KelpDecoratorFish kelpFish = new KelpDecoratorFish(new GreensDecoratorFish(new BlackFish()));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("c://a.txt")));
//对比上面两个语句,发现是不是结构一样呢?这两个模式是一样的,所以IO里面也是用了装饰者设计模式代替继承
}
}
运行结果:
从上面的uml和代码中可以看出,使用装饰者模式比继承使用的类更少;其次,装饰者模式比继承模式更加灵活,这是因为装饰者模式是动态的增强被装饰的对象,而继承是静态的;最后,装饰者设计模式的扩展性和可维护性肯定比继承要好。
装饰者模式就介绍到这里,如有错误欢迎指出,谢谢!
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/111235.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...