编程语言
首页 > 编程语言> > JAVA中容器设计的进化史:从白盒到黑盒,再到跻身为设计模式之一的迭代器

JAVA中容器设计的进化史:从白盒到黑盒,再到跻身为设计模式之一的迭代器

作者:互联网

在我们的项目编码中,不可避免的会用到一些容器类,我们可以直接使用ListMapSetArray等类型。当然,为了体现业务层面的含义,我们也会根据实际需要自行封装一些专门的Bean类,并在其中封装集合数据来使用。

看下面的一个场景:

在一个企业级的研发项目事务管理系统里面,包含很多的项目,每个项目下面又包含很多的具体需求,而每个需求下面又会被拆分出若干的具体事项。

按照常规思路,我们会怎么去建模呢?为了简化描述,我们仅以项目--需求--任务这个维度来说明下。

首先肯定会去创建Project(项目)、Requirement(需求)、Task(任务)三个类,然后每个类中会包含一个子对象的集合。比如对于Project而言,会包含一个Requirement的集合:

@Data
public class Project {
    private List<Requirement> requirements;
    private int status;
    private String projectName;
    // ...
}

同样道理,我们定义Requirement的时候,也会包含一个Task的集合:

@Data
public class Requirement {
    private List<Task> tasks;
    private int status;
    private String requirementName;
    private Date createTime;
    private Date closeTime;
    // ...
}

上述的例子中,ProjectRequirement便是两个典型的“容器”,容器中会存储着若干具体的元素对象。对容器而言,遍历容器内的元素是无法绕过的一个基本操作。

按照上面的容器对象定义实现,在业务逻辑代码中,需要获取某个Project中所有已关闭的需求事项列表,并按照创建时间降序排列,我们要如何做:先从容器中取出所有的需求集合,然后自行对此需求集合进行过滤、排序等操作

public List<Requirement> getAllClosedRequirements(Project project) {
    return project.getRequirements().stream()
            .filter(requirement -> requirement.getStatus() ==  1)
            .sorted((o1, o2) -> (int) (o2.getCreateTime().getTime() - o1.getCreateTime().getTime()))
            .collect(Collectors.toList());
}

或者,也可能会写成如下更为通俗的处理逻辑:

public List<Requirement> getAllClosedRequirements(Project project) {
    List<Requirement> requirements = project.getRequirements();
    List<Requirement> resultList = new ArrayList<>();
    for (Requirement requirement : requirements) {
        if (requirement.getStatus() == 1) {
            resultList.add(requirement);
        }
    }
    resultList.sort((o1, o2) -> (int) (o2.getCreateTime().getTime() - o1.getCreateTime().getTime()));
    return resultList;
}

很司空见惯的逻辑,的确也没有什么问题。但是,其实我们仅仅只是需要遍历容器中所有的元素,然后找出符合需要的内容,而Project类通过getRequirements()方法将整个内部存储List对象给出来让调用方直接去操作,存在一定的弊端

进一步思考下,其实我们只是想要遍历获取到容器中的元素,是否有更优雅的方式能够实现这一简单诉求,并且还能顺带解决上述这几个小遗憾呢?

带着疑问,我们一起来梳理下容器的演进历程,聊聊作为一个容器应该具备怎样的自我修养吧。

最直白的白盒容器

如上文中所提供的例子场景。示例中直接通过get方法将容器内管理的元素集合给暴露出去,任由调用方自行去处理使用。调用端需要知道这是一个元素集合是一个List类型还是一个Map类型,然后再根据不同类型,决定应该如何去遍历其中的元素,去对其中的元素进行操作。

白盒容器是一个典型的甩手掌柜式的容器,因为它要做的事情非常简单:给个get方法即可!任何调用方都可以直接获取到容器内部的真正元素存储集合,然后自行去对集合做各种操作,而容器则完全不管。

这样有一定的优势

但是呢,原本我们只是想遍历下容器中所有的元素内容,但是容器却直接将整个家底都交了出来。这就好比小王去小李家想看看小李家的猪里面有几只是母猪,而小李直接将猪圈丢给了小王,让小王自己进猪圈去数一样,这也太不把小王当外人了不是,谁知道小王进去是不是仅仅只是去数了下有几只母猪呢?

由此带来的弊端也就很明显了:

举个简单的例子:

当前Project中采用List来存储项目下所有的需求数据,而所有的调用端都是按照List的格式来处理需求数据。如果现在需要将Project中改为使用Map来存储需求数据,则原先所有通过project.getRequirements()获取需求数据的地方,都需要配套修改。

还是上面的例子:

业务调用方使用project.getRequirements()拿到List对象后,便可以对List进行add、remove、clear等各种操作。而很多时候,我们是需要保证对元素的内容的变更或者增减都在统一的地方去实行,这样可以保证数据的准确、也可以做一些统一处理,比如统一记录创建需求的日志之类的。而写操作入口变得不确定,使得整个数据的维护就存在很大的漏洞。

标签:Java,容器设计,项目编码,场景,任务,编辑,Project,代码
来源: