
本文探讨在 java/kotlin 中为小型、静态结构的 pojo 集合设计轻量级查询方案:推荐基于 specification 模式实现内存内条件过滤,避免冗余多索引维护;同时兼顾未来持久化扩展性。
本文探讨在 java/kotlin 中为小型、静态结构的 pojo 集合设计轻量级查询方案:推荐基于 specification 模式实现内存内条件过滤,避免冗余多索引维护;同时兼顾未来持久化扩展性。
在管理应用运行时状态(如配置、会话元数据、缓存实体)时,数据规模小(通常 既要支持灵活查询,又要避免为每个字段维护独立 Map 带来的内存开销、同步复杂度与代码膨胀。
✅ 推荐方案:Specification 模式(内存优先,零索引)
相比为 a、b、c 字段分别构建 HashMap,更优雅的解法是——不预建索引,而是在查询时对原始集合做高效过滤。这依赖于现代 JVM 语言对函数式操作的原生支持,其时间复杂度虽为 O(n),但对小型数据集(n ≈ 10–500)实际性能远超索引维护成本,且逻辑清晰、易于测试与演进。
技术上面应用了三层结构,AJAX框架,URL重写等基础的开发。并用了动软的代码生成器及数据访问类,加进了一些自己用到的小功能,算是整理了一些自己的操作类。系统设计上面说不出用什么模式,大体设计是后台分两级分类,设置好一级之后,再设置二级并选择栏目类型,如内容,列表,上传文件,新窗口等。这样就可以生成无限多个二级分类,也就是网站栏目。对于扩展性来说,如果有新的需求可以直接加一个栏目类型并新加功能操作
Kotlin 实现(简洁、类型安全、可组合)
interface Specification<T> {
fun isSatisfiedBy(obj: T): Boolean
}
// 基础谓词:字段值匹配
class FieldValue<T, V>(private val getter: (T) -> V, private val target: V) : Specification<T> {
override fun isSatisfiedBy(obj: T) = getter(obj) == target
}
// 组合逻辑:AND / OR
class And<T>(private val left: Specification<T>, private val right: Specification<T>) : Specification<T> {
override fun isSatisfiedBy(obj: T) = left.isSatisfiedBy(obj) && right.isSatisfiedBy(obj)
}
class Or<T>(private val left: Specification<T>, private val right: Specification<T>) : Specification<T> {
override fun isSatisfiedBy(obj: T) = left.isSatisfiedBy(obj) || right.isSatisfiedBy(obj)
}
// 使用示例
val data = listOf(
MyObject(1, "abc", true),
MyObject(2, "def", false),
MyObject(5, "abc", true)
)
// 查询:a == 5 或 (b == "abc" 且 c == true)
val query = Or(
FieldValue(MyObject::a, 5),
And(FieldValue(MyObject::b, "abc"), FieldValue(MyObject::c, true))
)
val results = data.filter(query::isSatisfiedBy) // 返回匹配的 MyObject 列表Java 实现(兼容至 Java 8+,利用 Lambda 与 FunctionalInterface)
@FunctionalInterface
interface Specification<T> {
boolean isSatisfiedBy(T obj);
}
// 工厂方法提升可读性
class Specifications {
public static <T, V> Specification<T> fieldEquals(Function<T, V> getter, V value) {
return obj -> Objects.equals(getter.apply(obj), value);
}
public static <T> Specification<T> and(Specification<T> a, Specification<T> b) {
return obj -> a.isSatisfiedBy(obj) && b.isSatisfiedBy(obj);
}
public static <T> Specification<T> or(Specification<T> a, Specification<T> b) {
return obj -> a.isSatisfiedBy(obj) || b.isSatisfiedBy(obj);
}
}
// 使用
List<MyObject> data = List.of(
new MyObject(1, "abc", true),
new MyObject(5, "xyz", false)
);
Specification<MyObject> query = Specifications.or(
Specifications.fieldEquals(MyObject::getA, 5),
Specifications.and(
Specifications.fieldEquals(MyObject::getB, "abc"),
Specifications.fieldEquals(MyObject::isC, true)
)
);
List<MyObject> results = data.stream()
.filter(query::isSatisfiedBy)
.collect(Collectors.toList());⚠️ 关键注意事项与演进建议
- 性能边界明确:该方案适用于 size ≤ 1000 的场景。若未来数据增长至数千条且查询高频,可平滑升级为 Eclipse Collections 的 MutableList + select(),或引入 MapDB(嵌入式、ACID、支持索引)。
- Kotlin 优势显著:属性引用(MyObject::a)、高阶函数、扩展函数使 Specification 构建更安全、更简短;Java 版需注意 Function 泛型推导和空值处理(建议配合 Optional 或 Objects.equals)。
-
持久化扩展路径清晰(回答第 3 问):
- 短期:序列化为 JSON(如 Jackson/Gson)存文件或 Redis;
- 中期:使用 H2(内存/文件模式)或 SQLite,建表后通过 JPA/Hibernate 或纯 JDBC 查询;
- 长期:若需跨进程共享,选 PostgreSQL + Flyway 迁移。所有方案均可复用同一套 Specification 接口——只需将 filter() 替换为 JPARepository.findAll(spec)(Spring Data JPA 支持 JpaSpecificationExecutor)或 SQL 生成器。
总结:对小型状态数据,「按需过滤」优于「预先索引」。Specification 模式以极低的认知与维护成本,提供可组合、可测试、可演进的查询能力,并天然桥接内存与持久化层——这是面向演进式架构的务实之选。









