装饰模式
装饰模式的定义:动态地给一个对象添加额外的职责,就添加功能来说,装饰模式比生成子类更加灵活。
这段话比较抽象,自己根据装饰模式实践了一下,有了一些小小的领悟分享一下。
我们最开始有一抽象类,比如说是人,它有两个子类分别是学生和老师,并且有一些共有的属性放在抽象类“人”中,有一些独有的属性放在各自的学生类和老师类中。并且有一个虚函数要学生和老师类来实现。
这模拟的是我们已经有一个生态系统了。
Person类:
public abstract class Person{
public String name = "";
public int age = 0;
public abstract void show();
}
Student类:
public class Student extends Person {
private int grade = 0;
public Student(String name, int age, int grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
@Override
public void show() {
System.out.println("Student "+name+"'s age is "+age+" in grade "+grade);
}
}
teacher类:
public class Teacher extends Person {
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public void show() {
System.out.println("Teacher "+name+"'s age is "+age);
}
}
现在我们需要向Person添加一个功能,给每个人穿衣服并且显示每个人的穿着。
在Person类中添加一个虚函数,再在各个类中实现穿衣这个穿衣函数,但是这种方法即难以实现又违背了开闭原则,因为会去更改每个类。
装饰模式提供了一种很好的解决方案:
定义一个接口,我的理解是定义一个需要添加的功能的接口,比如此种情况,我们定义一个Dress接口:
public interface Dress {
public void dressing();
}
然后先对这个接口编写各种衣服的类,所以先抽象出来一个衣物类Finary,它实现了接口。Finary的构造函数很重要,它指定需要装饰哪个对象的Dress接口
public class Finery implements Dress {
private Dress dress = null;
public Finery(Dress dress) {
this.dress = dress;
}
@Override
public void dressing() {
if(null != dress) {
dress.dressing();
System.out.println("Dressing:");
}
}
}
然后创建各项衣物类Finary的子类比如Tshirt、suit、tie。。。类
public class TShirt extends Finery{
public TShirt(Dress dress) {
super(dress);
}
@Override
public void dressing() {
super.dressing();
System.out.println("TShirt");
}
}
public class WearSuit extends Finery {
public WearSuit(Dress dress) {
super(dress);
}
@Override
public void dressing() {
super.dressing();
System.out.println("WearSuit");
}
}
public class WearTie extends Finery{
public WearTie(Dress dress) {
super(dress);
}
@Override
public void dressing() {
super.dressing();
System.out.println("WearTie");
}
}
然后是Person针对接口编程,因为每个人都需要穿衣服,并且都需要穿内衣……
public abstract class Person implements Dress{
public String name = "";
public int age = 0;
@Override
public void dressing() {
System.out.println("Dressing: UnderWear");
}
public abstract void show();
}
对于student和teacher类这里不需要重写dressing(),这是装饰模式最重要的应用点!!!即不需要修改已经实例化的Person子类,只需要抽象类Person针对接口编程,符合开闭原则,完美啊!!!
最后来看下是怎么调用的:
public static void main(String[] args) {
Person person = new Student("peter",15,2);
person.show();
Dress studentDress = person;
studentDress = new TShirt(studentDress);
studentDress = new BigTrousers(studentDress);
studentDress.dressing();
person = new Teacher("jobey",35);
person.show();
Dress teacherDress = person;
teacherDress = new WearSuit(teacherDress);
teacherDress = new WearTie(teacherDress);
teacherDress.dressing();
}
我们new一个student的时候,不仅实例化了一个学生对象,并且也实现了一个Dress接口,原来student的内容不需要改,要给每个学生穿衣服只需要将person的Dress接口提取出来:
Dress studentDress = person;
然后对person的Dress接口“穿衣服”就行了!!!
此处就是对实例化了的stduent的Dress接口studentDress进行“穿衣服”:
studentDress = new TShirt(studentDress);
studentDress = new BigTrousers(studentDress);
studentDress.dressing();
输出结果:
Student peter's age is 15 in grade 2
Dressing: UnderWear
Dressing: TShirt
Dressing: BigTrousers
Teacher jobey's age is 35
Dressing: UnderWear
Dressing: WearSuit
Dressing: WearTie
studentDress.dressing();
首先调用的是Person实现的dressing(),我的理解是毕竟这是new person才创建的接口嘛,之后是按“穿衣”顺序来调用dressing()函数。