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

关于装饰器模式

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

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

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

                            

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

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

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

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

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

业务描述:

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

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

1、项目目录说明:

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

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

猜你喜欢

转载自blog.csdn.net/weixin_40841731/article/details/84989983