第03章 - 核心架构解析

第03章 - 核心架构解析

3.1 项目结构概览

3.1.1 包结构

OGU4J采用清晰的分层架构,各包职责明确:

com.znlgis.ogu4j
├── datasource          # 数据源工具层
│   ├── OguLayerUtil    # 统一的图层读写工具
│   └── GtTxtUtil       # 国土TXT格式工具
├── engine              # GIS引擎核心层
│   ├── enums           # 枚举类型定义
│   ├── io              # 读写器接口
│   ├── model           # 数据模型
│   │   └── layer       # 图层模型
│   └── util            # 引擎工具类
├── exception           # 异常处理层
├── geometry            # 几何处理层
└── utils               # 通用工具层

3.1.2 层次依赖关系

┌─────────────────────────────────────────────────────────────┐
│                     datasource (数据源工具层)                │
│     OguLayerUtil, GtTxtUtil                                 │
├─────────────────────────────────────────────────────────────┤
│                      engine (引擎核心层)                     │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   GisEngine  │  │  LayerReader│  │ LayerWriter │         │
│  │   Factory    │  │  Interface  │  │ Interface   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│  ┌─────────────────────────────────────────────────┐       │
│  │              model (数据模型)                     │       │
│  │  OguLayer, OguFeature, OguField, OguFieldValue  │       │
│  └─────────────────────────────────────────────────┘       │
│  ┌─────────────────────────────────────────────────┐       │
│  │              util (引擎工具)                      │       │
│  │  CrsUtil, ShpUtil, PostgisUtil, OgrUtil         │       │
│  └─────────────────────────────────────────────────┘       │
├─────────────────────────────────────────────────────────────┤
│  geometry (几何处理)  │  exception (异常)  │  utils (工具)   │
│     GeometryUtil      │   OguException     │   ZipUtil      │
│                       │   及其子类          │   EncodingUtil │
└─────────────────────────────────────────────────────────────┘

3.2 核心模块详解

3.2.1 datasource - 数据源工具层

这是面向开发者的顶层API,提供最简洁的数据访问接口。

OguLayerUtil

统一的图层读写工具类,是使用OGU4J最常用的入口:

/**
 * 数据源工具类,提供统一的图层读写接口
 * 屏蔽底层引擎差异,简化开发者调用
 */
public class OguLayerUtil {
    
    /**
     * 读取图层
     * @param dataFormatType 数据格式类型
     * @param path 数据路径(文件路径或连接字符串)
     * @param layerName 图层名称
     * @param attributeFilter 属性过滤条件(CQL表达式)
     * @param spatialFilter 空间过滤条件(WKT格式)
     * @param engineType 使用的GIS引擎
     * @return 统一的OguLayer对象
     */
    public static OguLayer readLayer(
        DataFormatType dataFormatType,
        String path,
        String layerName,
        String attributeFilter,
        String spatialFilter,
        GisEngineType engineType
    );
    
    /**
     * 写入图层
     * @param dataFormatType 数据格式类型
     * @param layer 要写入的图层
     * @param path 输出路径
     * @param layerName 图层名称
     * @param options 额外选项
     * @param engineType 使用的GIS引擎
     */
    public static void writeLayer(
        DataFormatType dataFormatType,
        OguLayer layer,
        String path,
        String layerName,
        Map<String, Object> options,
        GisEngineType engineType
    );
}

设计思想

  1. 统一入口:所有格式读写都通过同一方法
  2. 参数标准化:使用枚举确保类型安全
  3. 引擎透明:开发者无需了解底层引擎细节

GtTxtUtil

专门处理国土TXT坐标格式的工具类:

/**
 * 国土TXT坐标文件处理工具
 * 支持自然资源部门的标准TXT格式
 */
public class GtTxtUtil {
    
    /**
     * 读取TXT文件
     * @param txtPath TXT文件路径
     * @param options 读取选项
     * @return 图层对象
     */
    public static OguLayer loadTxt(String txtPath, Map<String, Object> options);
    
    /**
     * 保存为TXT文件
     * @param layer 图层对象
     * @param txtPath 输出路径
     * @param metadata 元数据信息
     * @param options 保存选项
     * @param zoneNumber 带号
     */
    public static void saveTxt(
        OguLayer layer, 
        String txtPath, 
        OguLayerMetadata metadata,
        Map<String, Object> options,
        int zoneNumber
    );
}

3.2.2 engine - 引擎核心层

引擎层是OGU4J的核心,实现了双引擎架构。

引擎接口设计

/**
 * GIS引擎接口
 * 定义了所有引擎必须实现的操作
 */
public interface GisEngine {
    
    /**
     * 获取图层读取器
     */
    LayerReader getReader();
    
    /**
     * 获取图层写入器
     */
    LayerWriter getWriter();
    
    /**
     * 获取引擎类型
     */
    GisEngineType getEngineType();
    
    /**
     * 检查引擎是否可用
     */
    boolean isAvailable();
}

引擎工厂

/**
 * GIS引擎工厂
 * 负责创建和管理引擎实例
 */
public class GisEngineFactory {
    
    // 引擎缓存
    private static final Map<GisEngineType, GisEngine> engines = new HashMap<>();
    
    /**
     * 获取引擎实例
     * @param engineType 引擎类型
     * @return 引擎实例
     */
    public static GisEngine getEngine(GisEngineType engineType) {
        return engines.computeIfAbsent(engineType, type -> {
            switch (type) {
                case GEOTOOLS:
                    return new GeoToolsEngine();
                case GDAL:
                    return new GdalEngine();
                default:
                    throw new EngineNotSupportedException("不支持的引擎类型: " + type);
            }
        });
    }
    
    /**
     * 获取默认引擎
     */
    public static GisEngine getDefaultEngine() {
        return getEngine(GisEngineType.GEOTOOLS);
    }
}

GeoTools引擎实现

/**
 * GeoTools引擎实现
 */
public class GeoToolsEngine implements GisEngine {
    
    private final GeoToolsLayerReader reader;
    private final GeoToolsLayerWriter writer;
    
    public GeoToolsEngine() {
        this.reader = new GeoToolsLayerReader();
        this.writer = new GeoToolsLayerWriter();
    }
    
    @Override
    public LayerReader getReader() {
        return reader;
    }
    
    @Override
    public LayerWriter getWriter() {
        return writer;
    }
    
    @Override
    public GisEngineType getEngineType() {
        return GisEngineType.GEOTOOLS;
    }
    
    @Override
    public boolean isAvailable() {
        return true; // GeoTools是纯Java实现,始终可用
    }
}

GDAL引擎实现

/**
 * GDAL引擎实现
 */
public class GdalEngine implements GisEngine {
    
    private static boolean initialized = false;
    
    public GdalEngine() {
        initGdal();
    }
    
    private synchronized void initGdal() {
        if (!initialized) {
            try {
                gdal.AllRegister();
                initialized = true;
            } catch (Exception e) {
                throw new EngineNotSupportedException("GDAL初始化失败", e);
            }
        }
    }
    
    @Override
    public boolean isAvailable() {
        return initialized;
    }
    
    // ... 其他实现
}

3.2.3 model - 数据模型层

数据模型是OGU4J的核心抽象,位于engine.model包中。

模型类关系图

┌─────────────────────────────────────────────────────────────────┐
│                          OguLayer                               │
│  - name: String                                                 │
│  - wkid: Integer                                                │
│  - geometryType: GeometryType                                   │
│  - fields: List<OguField>                                       │
│  - features: List<OguFeature>                                   │
│  - metadata: OguLayerMetadata                                   │
├─────────────────────────────────────────────────────────────────┤
│  + validate(): void                                             │
│  + filter(OguFeatureFilter): List<OguFeature>                   │
│  + getFeatureCount(): int                                       │
│  + toJSON(): String                                             │
│  + fromJSON(String): OguLayer                                   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ 1:n
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                         OguFeature                              │
│  - fid: String                                                  │
│  - wkt: String                                                  │
│  - attributes: Map<String, OguFieldValue>                       │
├─────────────────────────────────────────────────────────────────┤
│  + getValue(String): Object                                     │
│  + setValue(String, Object): void                               │
│  + getAttribute(String): OguFieldValue                          │
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ 1:n
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        OguFieldValue                            │
│  - value: Object                                                │
├─────────────────────────────────────────────────────────────────┤
│  + getStringValue(): String                                     │
│  + getIntValue(): Integer                                       │
│  + getDoubleValue(): Double                                     │
│  + getDateValue(): Date                                         │
└─────────────────────────────────────────────────────────────────┘

为什么使用WKT存储几何

OGU4J选择使用WKT(Well-Known Text)格式存储几何数据,这是一个深思熟虑的设计决策:

方案 优点 缺点
JTS Geometry对象 直接使用,无需转换 与JTS强耦合
二进制WKB 存储效率高 不便调试
WKT字符串 跨库兼容、易读、易于序列化 存储稍大

WKT作为国际标准格式,可以轻松与任何GIS库交互。

3.2.4 geometry - 几何处理层

GeometryUtil是几何处理的核心类,提供两套API:

/**
 * 几何处理工具类
 * 基于JTS和ESRI Geometry API
 */
public class GeometryUtil {
    
    // ========== 基于JTS Geometry对象的方法 ==========
    
    // 格式转换
    public static Geometry wkt2Geometry(String wkt);
    public static String geometry2Wkt(Geometry geom);
    
    // 空间关系
    public static boolean intersects(Geometry a, Geometry b);
    public static boolean contains(Geometry a, Geometry b);
    
    // 空间分析
    public static Geometry buffer(Geometry geom, double distance);
    public static Geometry intersection(Geometry a, Geometry b);
    
    // ========== 基于WKT字符串的方法(使用ESRI API) ==========
    
    // 空间关系
    public static boolean intersectsWkt(String wktA, String wktB, int wkid);
    public static boolean containsWkt(String wktA, String wktB, int wkid);
    
    // 空间分析
    public static String bufferWkt(String wkt, int wkid, double distance);
    public static String intersectionWkt(String wktA, String wktB, int wkid);
}

两套API的设计理由

  1. JTS方法:适合需要多次操作几何对象的场景
  2. WKT方法:适合简单场景,避免对象转换开销

3.2.5 exception - 异常处理层

OGU4J设计了层次化的异常体系:

/**
 * OGU4J基础异常
 */
public class OguException extends RuntimeException {
    public OguException(String message) {
        super(message);
    }
    
    public OguException(String message, Throwable cause) {
        super(message, cause);
    }
}

/**
 * 数据源异常 - 数据读写相关错误
 */
public class DataSourceException extends OguException {
    // 文件不存在、连接失败等
}

/**
 * 格式解析异常 - 数据格式相关错误
 */
public class FormatParseException extends OguException {
    // WKT解析错误、JSON格式错误等
}

/**
 * 引擎不支持异常 - 引擎功能限制
 */
public class EngineNotSupportedException extends OguException {
    // GDAL未安装、格式不支持等
}

/**
 * 图层验证异常 - 数据完整性错误
 */
public class LayerValidationException extends OguException {
    // 字段缺失、几何无效等
}

/**
 * 拓扑异常 - 几何拓扑错误
 */
public class TopologyException extends OguException {
    // 自相交、环未闭合等
}

3.2.6 utils - 通用工具层

提供与GIS无关的通用工具:

// ZIP工具
public class ZipUtil {
    public static void zip(File folder, String zipPath);
    public static void zip(File folder, String zipPath, Charset charset);
    public static void unzip(String zipPath, String destPath);
    public static void unzip(String zipPath, String destPath, Charset charset);
}

// 编码检测工具
public class EncodingUtil {
    public static Charset getFileEncoding(File file);
}

// 自然排序工具
public class SortUtil {
    public static int compareString(String s1, String s2);
}

// 数字工具
public class NumUtil {
    public static String getPlainString(double value);
}

3.3 设计模式应用

3.3.1 工厂模式

GisEngineFactory使用工厂模式创建引擎实例:

// 工厂模式 - 根据类型创建对应的引擎
GisEngine engine = GisEngineFactory.getEngine(GisEngineType.GEOTOOLS);

优点

  • 封装对象创建逻辑
  • 支持引擎缓存复用
  • 便于扩展新引擎

3.3.2 策略模式

引擎切换使用策略模式:

// 策略模式 - 不同策略(引擎)可互换
OguLayer layer = OguLayerUtil.readLayer(
    DataFormatType.SHP,
    path,
    null, null, null,
    GisEngineType.GEOTOOLS  // 策略1
    // GisEngineType.GDAL   // 策略2
);

优点

  • 算法(引擎实现)与使用分离
  • 运行时动态切换
  • 符合开闭原则

3.3.3 模板方法模式

Reader和Writer使用模板方法:

// LayerReader接口定义了读取模板
public interface LayerReader {
    OguLayer read(DataFormatType format, String path, 
                  String layerName, String attrFilter, 
                  String spatialFilter);
}

// 各实现类提供具体实现
public class GeoToolsLayerReader implements LayerReader {
    @Override
    public OguLayer read(...) {
        // GeoTools特定实现
    }
}

3.3.4 建造者模式

OguLayer支持链式构建:

// 建造者模式示例
OguLayer layer = new OguLayer();
layer.setName("示例图层")
     .setWkid(4490)
     .setGeometryType(GeometryType.POLYGON);

3.4 扩展点设计

3.4.1 添加新引擎

要添加新的GIS引擎,需要:

  1. 实现GisEngine接口
  2. 实现LayerReaderLayerWriter
  3. GisEngineFactory中注册
// 1. 实现引擎接口
public class NewEngine implements GisEngine {
    @Override
    public LayerReader getReader() { ... }
    
    @Override
    public LayerWriter getWriter() { ... }
    
    @Override
    public GisEngineType getEngineType() { 
        return GisEngineType.NEW_ENGINE; 
    }
}

// 2. 在工厂中注册
case NEW_ENGINE:
    return new NewEngine();

3.4.2 添加新数据格式

要支持新的数据格式:

  1. DataFormatType中添加枚举值
  2. 在对应引擎的Reader/Writer中实现处理逻辑
// 1. 添加格式枚举
public enum DataFormatType {
    SHP, GEOJSON, FILEGDB, POSTGIS,
    NEW_FORMAT  // 新格式
}

// 2. 在Reader中处理
case NEW_FORMAT:
    return readNewFormat(path, layerName);

3.4.3 添加新几何操作

GeometryUtil中添加新方法:

/**
 * 新增几何操作
 */
public static Geometry newOperation(Geometry geom, Object params) {
    // 使用JTS或ESRI API实现
}

/**
 * WKT版本
 */
public static String newOperationWkt(String wkt, Object params) {
    // WKT版本实现
}

3.5 线程安全性

3.5.1 线程安全的类

  • GeometryUtil:所有方法都是无状态的静态方法,线程安全
  • CrsUtil:使用synchronized确保线程安全
  • GisEngineFactory:使用ConcurrentHashMap,线程安全

3.5.2 非线程安全的类

  • OguLayer:数据容器,不保证线程安全
  • OguFeature:数据容器,不保证线程安全
  • GeoToolsLayerReader/Writer:非线程安全,建议每次操作创建新实例

3.5.3 并发使用建议

// 推荐:在多线程环境中为每个任务创建独立的Layer
ExecutorService executor = Executors.newFixedThreadPool(4);

for (String shpFile : shpFiles) {
    executor.submit(() -> {
        // 每个线程读取自己的图层
        OguLayer layer = OguLayerUtil.readLayer(
            DataFormatType.SHP, shpFile, 
            null, null, null, 
            GisEngineType.GEOTOOLS
        );
        // 处理...
    });
}

3.6 性能考量

3.6.1 引擎选择

场景 推荐引擎 理由
一般用途 GeoTools 稳定、纯Java
大量数据 GDAL 性能更好
FileGDB GDAL GeoTools不支持
跨平台部署 GeoTools 无需本地库

3.6.2 内存优化

  • 大文件处理:使用流式读取,避免一次性加载
  • 几何缓存:避免重复创建Geometry对象
  • 及时释放:处理完成后置空引用

3.6.3 IO优化

  • 批量写入:使用事务批量提交
  • 合理过滤:在读取时使用过滤条件减少数据量
  • 连接池:PostGIS操作时使用连接池

← 上一章:快速入门与环境配置 | 下一章:统一图层模型详解 →

posted @ 2025-12-02 10:30  我才是银古  阅读(3)  评论(0)    收藏  举报