0

0

构建基于Map的Sort对象:一种工厂方法模式下的解决方案

聖光之護

聖光之護

发布时间:2025-11-07 11:59:01

|

576人浏览过

|

来源于php中文网

原创

构建基于Map的Sort对象:一种工厂方法模式下的解决方案

本文探讨了如何在java中,针对采用工厂方法模式(如`by()`和`and()`)且构造函数私有的`sort`类,从`map`动态构建`sort`对象。核心挑战在于首个排序条件的初始化方式不同于后续条件。解决方案是利用map迭代器,将第一个map条目用于`sort.by()`方法进行初始化,而将后续条目通过`sort.and()`方法链式添加,同时强调了map实现对排序顺序的重要性。

理解Sort对象的构建机制

在许多框架或自定义库中,Sort对象通常被设计为不可变或通过链式调用构建,以提供更清晰、更安全的API。常见的模式是提供一个静态工厂方法(如Sort.by())来创建初始的Sort实例,然后通过实例方法(如sort.and())来添加额外的排序条件。这种设计模式的特点是:

  1. 私有构造函数: 防止外部直接通过new Sort()创建实例,强制使用提供的工厂方法。
  2. 静态工厂方法by(): 用于创建第一个排序条件,并返回一个Sort实例。
  3. 实例方法and(): 用于在现有Sort实例上添加额外的排序条件,并返回当前Sort实例,支持链式调用。

当我们需要根据一个Map<WorklistColumn, Direction>(其中WorklistColumn是枚举类型,代表排序字段;Direction是枚举类型,代表升序或降序)动态构建Sort对象时,这种机制带来了一个挑战:Map中的第一个元素需要用by()方法处理,而后续所有元素都需要用and()方法处理。如果简单地遍历Map并尝试使用一个“虚拟”初始值来调用by(),再用and()添加所有实际值,会导致不必要的初始值或逻辑上的混乱。

基于迭代器构建Sort对象

为了优雅地解决上述问题,我们可以利用Map的entrySet()迭代器来区分处理第一个元素和后续元素。这种方法确保了Sort对象按照Map中定义的顺序正确初始化和构建。

Cursor
Cursor

一个新的IDE,使用AI来帮助您重构、理解、调试和编写代码。

下载

以下是实现此逻辑的详细步骤和示例代码:

  1. 处理空Map情况: 在开始构建之前,首先检查传入的columnsDirectionsMap是否为空。如果为空,则无法构建有效的Sort对象。根据业务需求,可以选择抛出异常(如NoCriteriaException)或返回一个表示无排序的默认对象。
  2. 获取Map的迭代器: 通过columnsDirectionsMap.entrySet().iterator()获取一个条目迭代器。
  3. 处理第一个元素: 使用iterator.next()获取Map中的第一个条目。这个条目将用于调用Sort.by()方法来初始化Sort对象。
  4. 处理后续元素: 使用while (criterionIterator.hasNext())循环遍历Map中剩余的所有条目。在循环内部,通过iterator.next()获取每个后续条目,并使用sort.and()方法将其添加到已初始化的Sort对象中。
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

// 假设 WorklistColumn 和 Direction 是已定义的枚举类型
enum WorklistColumn {
    NAME, AGE, DATE
}

enum Direction {
    ASCENDING, DESCENDING
}

// 模拟 Sort 类及其内部结构
class Sort {
    private List<Column> columns = new ArrayList<>();

    private Sort() {
        // 私有构造函数,强制使用静态工厂方法
    }

    // 静态工厂方法,用于创建带有第一个排序条件的Sort对象
    public static Sort by(String column) {
        return (new Sort()).and(column);
    }

    public static Sort by(String column, Direction direction) {
        return (new Sort()).and(column, direction);
    }

    // 实例方法,用于添加额外的排序条件
    public Sort and(String name) {
        this.columns.add(new Column(name));
        return this; // 返回当前实例,支持链式调用
    }

    public Sort and(String name, Direction direction) {
        this.columns.add(new Column(name, direction));
        return this; // 返回当前实例,支持链式调用
    }

    // 内部类 Column,用于表示单个排序字段及其方向
    private static class Column {
        String name;
        Direction direction;

        Column(String name) {
            this(name, Direction.ASCENDING); // 默认升序
        }

        Column(String name, Direction direction) {
            this.name = name;
            this.direction = direction;
        }

        @Override
        public String toString() {
            return name + " " + direction;
        }
    }

    @Override
    public String toString() {
        return "Sort{" +
               "columns=" + columns +
               '}';
    }
}

// 模拟异常类
class NoCriteriaException extends RuntimeException {
    public NoCriteriaException() {
        super("No sorting criteria provided.");
    }
}

public class SortBuilder {

    /**
     * 根据Map构建Sort对象。
     * Map中的第一个条目用于Sort.by()初始化,后续条目用于sort.and()链式添加。
     *
     * @param columnsDirectionsMap 包含排序字段和方向的Map。
     * @return 构建好的Sort对象。
     * @throws NoCriteriaException 如果传入的Map为空。
     */
    private Sort buildSort(Map<WorklistColumn, Direction> columnsDirectionsMap) {
        if (columnsDirectionsMap.isEmpty()) {
            throw new NoCriteriaException(); // 或者返回一个默认的空Sort对象
        }

        Iterator<Map.Entry<WorklistColumn, Direction>> criterionIterator =
                columnsDirectionsMap.entrySet().iterator();

        // 处理第一个条目
        Map.Entry<WorklistColumn, Direction> firstCriterion = criterionIterator.next();
        Sort sort = Sort.by(firstCriterion.getKey().toString(), firstCriterion.getValue());

        // 处理剩余条目
        while (criterionIterator.hasNext()) {
            Map.Entry<WorklistColumn, Direction> nextCriterion = criterionIterator.next();
            sort.and(nextCriterion.getKey().toString(), nextCriterion.getValue());
        }

        return sort;
    }

    public static void main(String[] args) {
        SortBuilder builder = new SortBuilder();

        // 示例1: 使用LinkedHashMap保持插入顺序
        Map<WorklistColumn, Direction> map1 = new LinkedHashMap<>();
        map1.put(WorklistColumn.NAME, Direction.ASCENDING);
        map1.put(WorklistColumn.AGE, Direction.DESCENDING);
        map1.put(WorklistColumn.DATE, Direction.ASCENDING);

        Sort sort1 = builder.buildSort(map1);
        System.out.println("Sort object from LinkedHashMap: " + sort1);
        // 预期输出: Sort{columns=[NAME ASCENDING, AGE DESCENDING, DATE ASCENDING]}

        // 示例2: 使用HashMap (顺序不可预测)
        Map<WorklistColumn, Direction> map2 = new HashMap<>();
        map2.put(WorklistColumn.DATE, Direction.DESCENDING);
        map2.put(WorklistColumn.NAME, Direction.ASCENDING);
        map2.put(WorklistColumn.AGE, Direction.ASCENDING);

        Sort sort2 = builder.buildSort(map2);
        System.out.println("Sort object from HashMap (order may vary): " + sort2);
        // 实际输出顺序可能与插入顺序不同

        // 示例3: 空Map处理
        Map<WorklistColumn, Direction> emptyMap = new LinkedHashMap<>();
        try {
            builder.buildSort(emptyMap);
        } catch (NoCriteriaException e) {
            System.out.println("Caught expected exception for empty map: " + e.getMessage());
        }
    }
}

注意事项

  1. Map的顺序性: 这种构建方式高度依赖于Map中条目的迭代顺序。如果排序条件的顺序对业务逻辑至关重要,则必须使用能够保证插入顺序的Map实现,例如LinkedHashMap。HashMap不保证任何特定的迭代顺序,因此不适用于此场景,其结果可能不符合预期。
  2. 异常处理: 当传入的columnsDirectionsMap为空时,criterionIterator.next()将抛出NoSuchElementException。因此,在调用next()之前,务必进行空Map检查并进行适当的异常处理或返回默认值。
  3. 类型转换: 示例中将WorklistColumn枚举转换为String类型(criterion.getKey().toString()),这取决于Sort.by()和Sort.and()方法期望的参数类型。请确保进行正确的类型转换。

总结

通过巧妙地利用Map的迭代器,我们可以优雅地处理Sort类这种采用工厂方法模式的构建机制,将Map中的第一个元素用于初始化,后续元素通过链式调用添加。这种方法不仅解决了特定API设计带来的挑战,还保持了代码的清晰性和可维护性。在实际应用中,选择合适的Map实现(如LinkedHashMap)以保证排序条件的顺序至关重要,同时也要妥善处理空Map的情况,以增强代码的健壮性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1051

2023.08.02

sort排序函数用法
sort排序函数用法

sort排序函数的用法:1、对列表进行排序,默认情况下,sort函数按升序排序,因此最终输出的结果是按从小到大的顺序排列的;2、对元组进行排序,默认情况下,sort函数按元素的大小进行排序,因此最终输出的结果是按从小到大的顺序排列的;3、对字典进行排序,由于字典是无序的,因此排序后的结果仍然是原来的字典,使用一个lambda表达式作为key参数的值,用于指定排序的依据。

409

2023.09.04

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

107

2023.09.25

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

47

2025.11.27

C++类型转换方式
C++类型转换方式

本专题整合了C++类型转换相关内容,想了解更多相关内容,请阅读专题下面的文章。

320

2025.07.15

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 81.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号