区别
装饰者 | 继承 | |
---|---|---|
优势 | 代码灵活性高、耦合度低、扩展性强 | 代码结构清晰、实现简单 |
缺陷 | 大量使用多态维护实例使得代码稍复杂 | 程序臃肿、子类爆炸 |
装饰器
IO中用的最多的就是装饰器模式~
- 装饰器模式是什么:通过
包装原有类
来实现增强对象
的一种设计模式 - 装饰器模式作用: 在实现
增强对象
的前提下,避免程序臃肿,降低耦合度
使用场景
- 扩展一个类的功能。
- 动态增加功能,动态撤销
- 继承关系会出现过多子类时
示例
- 先来一个
Person
接口
public interface Person {
void eat();
}
- 实现接口得到
Man
父类
public class Man implements Person{
@Override
public void eat() {
System.out.println("吃饭...");
}
}
- 装饰
Man
的SuperMan
装饰(器)类
public abstract class SuperMan implements Person{
private Person person;
public SuperMan(Person person) {
this.person = person;
}
@Override
public void eat() {
person.eat();
}
}
- 需求:不修改
Man
类的前提下,实现“吃饭”前要先“洗手” - 用继承方式实现
- 第一步:继承
Man
类并增加洗手的方法
public class CleanMan extends Man{
public void wash() {
System.out.println("洗手...");
}
@Override
public void eat(){
wash();
super.eat();
}
}
- 第二步:创建对象调用增强后的方法
public static void main(String[] args) {
// 创建对象
Man cleanMan = new CleanMan();
// 调用增强过的eat()方法
cleanMan.eat();
}
结果:
洗手…
吃饭…
- 用装饰器实现
- 第一步:继承
Man
的装饰类
public class CleanSuperMan extends SuperMan{
public CleanSuperMan(Person person) {
super(person);
}
// 扩展功能
public void wash() {
System.out.println("洗手...");
}
// 实现吃饭前先洗手
@Override
public void eat() {
wash();
super.eat();
}
}
- 第二步:创建对象并装饰
public class Mian {
public static void main(String[] args) {
// 原本实现类
Person man = new Man();
// 装饰他
man = new CleanSuperMan(man);
man.eat();
}
}
结果:
洗手…
吃饭…
- 上面的例子通过继承和装饰器模式都实现了对象功能的增强,甚至看起来装饰器模式还比继承麻烦许多。
- 那么问题来了,我们何必要用装饰器?
- 现在我们更换需求:“吃饭”前不“洗手”了
用装饰器实现
- 不再装饰man对象就ok了
public class Mian {
public static void main(String[] args) {
// 原本实现类
Person man = new Man();
// 装饰他
//man = new CleanSuperMan(man);
man.eat();
}
}
用继承实现
- 在Man的子类CleanMan中去掉wash()方法的调用
public class CleanMan extends Man{
public void wash() {
System.out.println("洗手...");
}
@Override
public void eat(){
// wash();
super.eat();
}
}
差异
两种方式比较之下可以明显看出装饰者模式比继承灵活很多。
继承在改变需求时,要修改子类代码,这样就引出了一个问题,例如以上代码中不再需要wash()方法时,应该在增强后的类中完全去掉该方法,还是去掉它的调用?如果完全去掉那么后续需要时得重写,如果去掉调用,那么可能出现垃圾代码。而装饰者模式中,装饰器是独立于原本的代码之外的,由此可见,其大大解决了复杂的继承关系引起的子类爆炸问题。
IO中的装饰者模式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter("key.txt"));