关于装饰器模式

定义:装饰器模式又名包装(Wrapper)模式。装饰器模式以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案。

          重点:装饰器模式是继承关系的一种替代方案

装饰器模式的类图:(个人觉得理解这幅图很重要。可以先看完例子再回过头看本图。记住了本图,更容易在自己代码中灵活使用)

                            

装饰器模式在实际项目中的应用_编程语言

                        在装饰器模式中的角色有:

                        抽象构件(Component)角色:给出一个抽象接口,已规范准备接收附加责任的对象。、

                        具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类

                        装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。

                        具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任

 

 

业务描述:

       今天项目经理说有个页面的排序规则需要修改下。写这个类及方法的人不在,于是把这个需求抛给了我。(在这里想吐槽下:看自己的代码总觉得很完美,看别人的代码总觉得这他妈的写的什么,看都看不懂,注释也没有)。经过层层跟踪,终于搞懂所有逻辑。但是发现方法里查询了数据库,但是返回数据做了处理,不是数据库表对应的实体,根本没有实体,直接用的json数组合json对象,从新封装的。所以排序自然也不能写在sql里了。需要自己在代码里实现。其实直接可以用集合的排序实现的,但是为啥我不这样呢。主要是我又不想动别人写的任何代码,免得背锅。于是怎么办呢,最后决定采用装饰器设计模式进行改造。

       说明:项目中是:先根据状态排序,在根据编号排序。为了容易理解,这里就用用户的性别代表状态,年纪代表编号。 (旨在更容易理解装饰器模式,如有设计不足的地方,请忽略)

1、项目目录说明:

装饰器模式在实际项目中的应用_装饰器模式_02

2、抽象构件(Component)角色:SortingWithSets.java 接口

public interface SortingWithSets {
//对list排序
void sortingSets(List<User> list);
}

3、具体构件(ConcreteComponent)角色:SortingSetsBySex.java  根据性别排序类

public class SortingSetsBySex implements SortingWithSets {

@Override
public void sortingSets(List<User> list) {
list.sort(Comparator.comparing(user->((User)user).getSex()).reversed());
}

}

4、装饰(Decorator)角色: AbstractSortingWithSets.java 类:持有一个需要装饰的类及调用被装饰的类的方法

public abstract class AbstractSortingWithSets implements SortingWithSets{
//持有一个需要装饰的类
private SortingWithSets sortingWithSets;

public AbstractSortingWithSets(SortingWithSets sortingWithSets) {
super();
this.sortingWithSets = sortingWithSets;
}

@Override
public void sortingSets(List<User> list) {
//调用被装饰的类的方法
sortingWithSets.sortingSets(list);
}

}

5、具体装饰(ConcreteDecorator)角色:这里有两个类,根据年龄排序的类,和更加姓名排序的类

(1)、根据年龄排序的类:SortingSetsByAge.java 该类调用被装饰的类的排序方法,同时自己再实现自己排序规则

public class SortingSetsByAge extends AbstractSortingWithSets {
//构造方法,需要传被装饰的类
public SortingSetsByAge(SortingWithSets sortingWithSets) {
super(sortingWithSets);
}

@Override
public void sortingSets(List<User> list) {
//调用被装饰的类的排序方法
super.sortingSets(list);
//同时自己再实现自己排序规则
list.sort(Comparator.comparing(user->((User)user).getAge()));
}

}

(2)、根据姓名排序的类:SortingSetsByName.java 该类调用被装饰的类的排序方法,同时自己再实现自己排序规则

public class SortingSetsByName extends AbstractSortingWithSets {
//构造方法,需要传被装饰的类
public SortingSetsByName(SortingWithSets sortingWithSets) {
super(sortingWithSets);
}

@Override
public void sortingSets(List<User> list) {
//调用被装饰的类的排序方法
super.sortingSets(list);
//实现自己排序规则
list.sort(Comparator.comparing(user->((User)user).getName()));
}

}

6、测试类 Test.java

public class Test {

public static void main(String[] args) {
//加入下面就是源代码部分
List<User> list = new ArrayList<User>();
User user = new User("张三", "15", "男");
User user1 = new User("李四", "11", "男");
User user2 = new User("李四", "10", "男");
User user3 = new User("李四", "16", "男");
User user4 = new User("李四", "10", "男");
User user5 = new User("张曼玉2", "10", "女");
User user6 = new User("张曼玉1", "10", "女");
User user7 = new User("张曼玉3", "10", "女");
User user8 = new User("李四", "10", "男");
list.add(user);
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
list.add(user5);
list.add(user6);
list.add(user7);
list.add(user8);
//这里就是我要加的排序代码
SortingWithSets sort = new SortingSetsByAge(new SortingSetsBySex());
SortingWithSets sort1 = new SortingSetsByName(sort);
//这里的调用顺序是:先调用性别类中的根据性别排序,再调用根据年龄排序,最后调用根据姓名排序
sort1.sortingSets(list);
list.forEach(a->System.out.println(a));
}

}

结束!

结语:其实装饰器模式,用aop感觉也可以实现,不仅仅是aop,还有很多方式实现。 但是设计模式,更有他的魅力所在。

其实本例子中是有些瑕疵所在,实际项目中当然不是这样简单的处理的。用心的小伙伴儿,您能发现吗?

测试demo: ​​https://github.com/alwaysInRoad/test-decorator-demo.git​

 

如果觉得对您有用,乃是我莫大的欢喜