一、组合模式
组合模式是一种是数据结构或算法的抽象,将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。使用组合模式的前提在于,你的业务场景必须能够表示成树形结构,有整体和部分的关联关系。所以,组合模式的应用场景也比较局限,它并不是一种很常用的设计模式。——摘自王争《设计模式之美》
比如我们可以通过代码实现下面这种树形结构的遍历:
首先创建抽象类
/**
* 文件抽象类
*/
@Data
public abstract class File {
/**
* 文件名称
*/
public String fileName;
/**
* 构造方法
*/
File(String fileName) {
this.fileName = fileName;
}
/**
* 抽象方法:浏览
*/
public abstract void scan();
}
然后创建视频和文本类,这里只展示视频类,文本与其一样
/**
* 视频文件
*/
public class VedioFile extends File{
public VedioFile(String fileName) {
super(fileName);
}
@Override
public void scan() {
System.out.println("视频文件:" + fileName);
}
}
然后创建视频文件夹,文本文件夹与其一样
/**
* 视频文件夹:包含所有视频文件
*/
public class FolerVedio extends File{
/**
* 所有视频文件集合
*/
private List<File> vedioFiles;
/**
* 构造方法,将文件夹名称传入
*/
public FolerVedio(String folderName) {
super(folderName);
this.vedioFiles = Lists.newArrayList();
}
/**
* 浏览方法的实现类
*/
@Override
public void scan() {
for (File vedioFile : vedioFiles) {
vedioFile.scan();
}
}
/**
* 文件添加
*/
public void addFile(File file) {
vedioFiles.add(file);
}
/**
* 文件删除
*/
public boolean del(File file) {
return vedioFiles.remove(file);
}
}
最后创建一个大文件夹
/**
* 大文件夹
*/
public class Folder extends File {
private List<File> files;
public Folder(String folderName) {
super(folderName);
this.files = Lists.newArrayList();
}
/**
* 文件添加
*/
public void addFile(File file) {
files.add(file);
}
/**
* 文件删除
*/
public boolean del(File file) {
return files.remove(file);
}
@Override
public void scan() {
for (File file : files) {
file.scan();
}
}
}
测试打印结果:
@RunWith(JUnit4.class)
public class CombinationTest {
@Test
public void testCombination() {
//大文件夹
Folder folder = new Folder("大文件夹");
//创建多个视频文件夹并存入多个视频文件
for (int i = 0; i < 2; i++) {
FolerVedio folerVedio = new FolerVedio("文件夹vedio-" + i);
for (int j = 0; j < 5; j++) {
VedioFile vedioFile = new VedioFile("视频文件{"+ i +"-"+ j + "}");
folerVedio.addFile(vedioFile);
}
folder.addFile(folerVedio);
}
//创建多个文本文件夹并存入多个文本文件
for (int i = 0; i < 2; i++) {
FolerText folerText = new FolerText("文件夹text-" + i);
for (int j = 0; j < 2; j++) {
TextFile textFile = new TextFile("文本文件{"+ i +"-"+ j + "}");
folerText.addFile(textFile);
}
folder.addFile(folerText);
}
//文件浏览
folder.scan();
}
}
//打印结果:
视频文件:视频文件{0-0}
视频文件:视频文件{0-1}
视频文件:视频文件{0-2}
视频文件:视频文件{0-3}
视频文件:视频文件{0-4}
视频文件:视频文件{1-0}
视频文件:视频文件{1-1}
视频文件:视频文件{1-2}
视频文件:视频文件{1-3}
视频文件:视频文件{1-4}
文本文件:文本文件{0-0}
文本文件:文本文件{0-1}
文本文件:文本文件{1-0}
文本文件:文本文件{1-1}
二、享元模式
所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。具体来讲,当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,我们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。这样可以减少内存中对象的数量,起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段)提取出来,设计成享元,让这些大量相似对象引用这些享元。这里我稍微解释一下,定义中的“不可变对象”指的是,一旦通过构造函数初始化完成之后,它的状态(对象的成员变量或者属性)就不会再被修改了。所以,不可变对象不能暴露任何 set() 等修改内部状态的方法。之所以要求享元是不可变对象,那是因为它会被多处代码共享使用,避免一处代码对享元进行了修改,影响到其他使用它的代码。——摘自王争《设计模式之美》
在实际开发中,一般都会使用枚举类来进行各种判断和处理。
/**
* 商家类型
*/
@Getter
public enum AgencyTypeEnum {
TO_B(1, Sets.newHashSet("alibaba", "tencent"), "企业"),
TO_C(2, Sets.newHashSet("MaSaKi"), "个人");
/**
* 代号
*/
private int code;
/**
* set集合:包含商家名称
*/
private Set<String> agencyNames;
/**
* 描述
*/
private String desc;
/**
* 构造方法
*/
AgencyTypeEnum(int code, Set<String> agencyNames, String desc) {
this.code = code;
this.agencyNames = agencyNames;
this.desc = desc;
}
}
这其实就是一种享元模式的应用,非常简单,核心就是要减小内存空间的消耗。