应用场景:
我们有现在有一杯白开水,4种配料—糖,盐,茶叶,苏打。如果我们想要喝不同的水,就要加不同的配料,那怎样实现呢?可能我们的第一印象会想到使用继承:
- 首先定义一个白开水基类
- 对于加糖的,加盐的,加茶叶的 ,加苏打的,分别写一个子类继承
- 对于加糖,又加盐的写一个子类,
- 对于加糖,又加茶叶的写一个子类,
- 对于加糖、又加苏打的写一个子类,
- 对于加糖,又加盐、还加苏打的写一个子类 。。。。。。
说到这里,会发现只有四种配料就要写十几种实现类了,那如果我们的配料是二十几种或者三十几种呢,那么使用继承这种方式肯定会使我们的子类爆炸,那要怎样解决,答案就是使用装饰者模式。
1. 什么是装饰者模式
模式定义:
官方定义:装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
换而言之就是:在不改变原有对象的基础上,动态地将功能附加到对象上。
简单理解就是:原来有一个东西,觉得它不够好看,就在它上面加点装饰。
在装饰模式中的4个角色:
-
抽象构件角色:(Component):给出一个抽象接口,以规范准备接收附加责任的对象。
-
具体构件角色:(ConcreteComponent):定义一个将要接收附加责任的类。
-
装饰角色:(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
-
具体装饰角色:(ConcreteDecorator)负责给构件对象“贴上”附加的责任。
2. 怎样实现装饰者模式 ?
举个例子:三明治
//食物基类
Public Class Food{
Private String food_name;
Public Food(){}
Public Food(String food_name){
this.food_name=food_name;
}
Public String make(){
Return food_name;
}
}
//面包类
Public class Bread extends Food{
Private Food basic_food;
Public Bread(Food basic_food){
this.basic_food=basic_food;
}
Public String make(){
Return basic_food.make()+"+面包";
}
}
//奶油类
Public class Cream extends Food{
Private Food basic_food;
Public Cream(Food basic_food){
this.basic_food=basic_food;
}
Public String make(){
Return basic_food.make()+"+奶油";
}
}
//蔬菜类
Public class Vegetable extends Food{
Private Food basic_food;
Public Vegetable(Food basic_food){
this.basic_food=basic_food;
}
Public String make(){
Return basic_food.make()+"+蔬菜";
}
}
Public class Test{
Public static void main(String[]args){
Food food1=new Bread(new Cream(new Food("香肠")));
Food food2=new Bread(new Vegetable(new Cream(new Food("香肠"))));
System.out.println(food1.make());
System.out.println(food2.make());
}
}
分析food2:
-
Food food2=new Bread(new Vegetable(new Cream(new Food(“香肠”))));
-
一层一层封装,我们从里往外看:最里面new了个香肠,在香肠的外面包裹了一层奶油,在奶油的外面又加了一层蔬菜,最外面放的是面包,一层夹一层;
-
这个设计模式跟现实生活中一摸一样。用户在使用的时候,可以任意组装,达到自己想要的效果。
3. 装饰者模式的优点 ?
特点:
(1) 装饰对象和真实对象有相同的接口。
(2) 装饰对象包含一个真实对象的引用
优点:
(1) 不改变原有对象的情况下,给一个对象扩展功能。
(2) 装饰者灵活,使用不同的组合可以实现不同的效果。
(3) 符合开闭原则 — 对扩展开放,对修改关闭。
4. 装饰者模式在Java API中的应用
装饰模式在 Java 语言中的最著名的应用就是 Java I/O 标准库的设计。
例如:Reader 的子类 BufferedReader 以及 FilterReader,Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
5.What —开闭原则?
定义:
一个软件实体(如:类、模块和函数)应该对扩展开放,对修改关 闭。
其含义就是说:一个软件实体应该通过扩展来实现变化。
一个软件产品只要在生命周期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计时尽量适应这些变化,以提高项目的稳定性和灵活性,真正实现“拥抱变化”。
开放封闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。
单一职责原则有什么好处:
-
降低类的复杂度,一个类只负责一个职责。(这样写出来的代码逻辑肯定比负责多项职责的简单得多)
-
提高类的可读性,提高系统的可维护性。
-
降低变更引起的风险降低。(变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,提高了系统的扩展性、维护性)
注意
开闭原则对扩展开放,对修改封闭,并不意味着不做任何修改,低层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。