一个跨平台的全国主要城市铁路线查询APP,支持C++、Rust、Java三种语言搭建。
## 系统架构设计
### 1. 整体架构
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 前端UI层 │ │ 业务逻辑层 │ │ 数据访问层 │
│ (各平台实现) │◄──►│ (C++核心) │◄──►│ (Rust实现) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ │ │
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Android(Java) │ │ Windows/Linux │ │ 数据文件 │
│ iOS(Swift) │ │ (C++/Rust) │ │ 网络API │
│ Web(JS) │ │ macOS(C++/Rust)│ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
```
## C++核心实现
### 数据结构定义
```cpp
// railway_core.h
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
struct Station {
std::string id;
std::string name;
std::string city;
double latitude;
double longitude;
};
struct RailwaySegment {
std::string id;
std::string from_station;
std::string to_station;
double distance; // 公里
int travel_time; // 分钟
std::string train_type; // 高铁/动车/普速
};
class RailwayGraph {
private:
std::unordered_map<std::string, Station> stations;
std::unordered_map<std::string, std::vector<RailwaySegment>> adjacency_list;
public:
bool addStation(const Station& station);
bool addSegment(const RailwaySegment& segment);
std::vector<std::vector<RailwaySegment>> findRoutes(
const std::string& from, const std::string& to, int max_transfers = 2);
std::vector<Station> getStationsByCity(const std::string& city);
};
```
### 核心算法实现
```cpp
// railway_graph.cpp
#include "railway_core.h"
#include <queue>
#include <algorithm>
struct RouteNode {
std::string station_id;
std::vector<RailwaySegment> path;
double total_distance;
int total_time;
int transfers;
};
std::vector<std::vector<RailwaySegment>>
RailwayGraph::findRoutes(const std::string& from, const std::string& to, int max_transfers) {
std::vector<std::vector<RailwaySegment>> results;
auto cmp = [](const RouteNode& a, const RouteNode& b) {
return a.total_time > b.total_time; // 按时间优先
};
std::priority_queue<RouteNode, std::vector<RouteNode>, decltype(cmp)> pq(cmp);
// BFS算法寻找路径
pq.push({from, {}, 0, 0, 0});
while (!pq.empty()) {
auto current = pq.top();
pq.pop();
if (current.station_id == to) {
results.push_back(current.path);
continue;
}
if (current.transfers > max_transfers) continue;
for (const auto& segment : adjacency_list[current.station_id]) {
RouteNode next;
next.station_id = segment.to_station;
next.path = current.path;
next.path.push_back(segment);
next.total_distance = current.total_distance + segment.distance;
next.total_time = current.total_time + segment.travel_time;
next.transfers = current.transfers + (current.path.empty() ? 0 :
(segment.from_station != current.path.back().to_station) ? 1 : 0);
pq.push(next);
}
}
return results;
}
```
## Rust数据层实现
### 数据管理和序列化
```rust
// data_manager.rs
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::io;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Station {
pub id: String,
pub name: String,
pub city: String,
pub latitude: f64,
pub longitude: f64,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct RailwaySegment {
pub id: String,
pub from_station: String,
pub to_station: String,
pub distance: f64,
pub travel_time: i32,
pub train_type: String,
}
pub struct RailwayDataManager {
stations: HashMap<String, Station>,
segments: Vec<RailwaySegment>,
}
impl RailwayDataManager {
pub fn new() -> Self {
Self {
stations: HashMap::new(),
segments: Vec::new(),
}
}
pub fn load_from_json(&mut self, file_path: &str) -> io::Result<()> {
let data = fs::read_to_string(file_path)?;
let stations: Vec<Station> = serde_json::from_str(&data)?;
for station in stations {
self.stations.insert(station.id.clone(), station);
}
Ok(())
}
pub fn load_segments_from_json(&mut self, file_path: &str) -> io::Result<()> {
let data = fs::read_to_string(file_path)?;
let segments: Vec<RailwaySegment> = serde_json::from_str(&data)?;
self.segments = segments;
Ok(())
}
pub fn get_station(&self, id: &str) -> Option<&Station> {
self.stations.get(id)
}
pub fn get_city_stations(&self, city: &str) -> Vec<&Station> {
self.stations.values()
.filter(|s| s.city == city)
.collect()
}
pub fn get_segments_from_station(&self, station_id: &str) -> Vec<&RailwaySegment> {
self.segments.iter()
.filter(|s| s.from_station == station_id)
.collect()
}
}
```
### 网络数据获取
```rust
// network_manager.rs
use reqwest;
use serde_json::Value;
use std::collections::HashMap;
pub struct NetworkManager {
client: reqwest::Client,
base_url: String,
}
impl NetworkManager {
pub fn new() -> Self {
Self {
client: reqwest::Client::new(),
base_url: "https://api.railway.com".to_string(),
}
}
pub async fn search_real_time_schedule(
&self,
from_city: &str,
to_city: &str
) -> Result<Value, reqwest::Error> {
let url = format!("{}/api/schedule", self.base_url);
let params = HashMap::from([
("from", from_city),
("to", to_city),
]);
let response = self.client.get(&url)
.query(¶ms)
.send()
.await?
.json::<Value>()
.await?;
Ok(response)
}
}
```
## Java Android前端实现
### 主Activity
```java
// MainActivity.java
package com.railway.query;
import android.os.Bundle;
import android.widget.*;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private Spinner fromCitySpinner, toCitySpinner;
private Button searchButton;
private ListView resultListView;
private RailwayQueryManager queryManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
setupQueryManager();
setupEventListeners();
}
private void initViews() {
fromCitySpinner = findViewById(R.id.from_city_spinner);
toCitySpinner = findViewById(R.id.to_city_spinner);
searchButton = findViewById(R.id.search_button);
resultListView = findViewById(R.id.result_listview);
// 初始化城市数据
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.cities_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
fromCitySpinner.setAdapter(adapter);
toCitySpinner.setAdapter(adapter);
}
private void setupQueryManager() {
queryManager = new RailwayQueryManager(this);
queryManager.initializeData();
}
private void setupEventListeners() {
searchButton.setOnClickListener(v -> performSearch());
}
private void performSearch() {
String fromCity = fromCitySpinner.getSelectedItem().toString();
String toCity = toCitySpinner.getSelectedItem().toString();
if (fromCity.equals(toCity)) {
Toast.makeText(this, "出发城市和到达城市不能相同", Toast.LENGTH_SHORT).show();
return;
}
List<RouteResult> results = queryManager.searchRoutes(fromCity, toCity);
displayResults(results);
}
private void displayResults(List<RouteResult> results) {
RouteAdapter adapter = new RouteAdapter(this, results);
resultListView.setAdapter(adapter);
resultListView.setOnItemClickListener((parent, view, position, id) -> {
RouteResult selectedRoute = results.get(position);
showRouteDetails(selectedRoute);
});
}
private void showRouteDetails(RouteResult route) {
// 显示路线详情对话框
RouteDetailDialog dialog = new RouteDetailDialog(this, route);
dialog.show();
}
}
```
### 路线适配器
```java
// RouteAdapter.java
package com.railway.query;
import android.view.*;
import android.widget.*;
import java.util.List;
import androidx.annotation.NonNull;
public class RouteAdapter extends ArrayAdapter<RouteResult> {
private final int resourceId;
public RouteAdapter(android.content.Context context, List<RouteResult> results) {
super(context, R.layout.item_route, results);
this.resourceId = R.layout.item_route;
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
RouteResult route = getItem(position);
View view = convertView != null ? convertView :
LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
TextView routeInfo = view.findViewById(R.id.route_info);
TextView duration = view.findViewById(R.id.duration);
TextView transfers = view.findViewById(R.id.transfers);
if (route != null) {
routeInfo.setText(String.format("%s → %s",
route.getFromStation(), route.getToStation()));
duration.setText(String.format("耗时: %d分钟", route.getTotalTime()));
transfers.setText(String.format("换乘: %d次", route.getTransferCount()));
}
return view;
}
}
```
## 数据文件示例
### 车站素材 (stations.json)
```json
{
"stations": [
{
"id": "BJ",
"name": "北京南站",
"city": "北京",
"latitude": 39.865,
"longitude": 116.378
},
{
"id": "SH",
"name": "上海虹桥站",
"city": "上海",
"latitude": 31.194,
"longitude": 121.319
},
{
"id": "GZ",
"name": "广州南站",
"city": "广州",
"latitude": 23.990,
"longitude": 113.271
}
]
}
```
## 跨平台接口设计
### C++/Rust FFI接口
```rust
// ffi_bridge.rs
use std::os::raw::c_char;
use std::ffi::{CStr, CString};
#[no_mangle]
pub extern "C" fn railway_search_routes(
from_city: *const c_char,
to_city: *const c_char
) -> *mut c_char {
let from_str = unsafe { CStr::from_ptr(from_city).to_str().unwrap() };
let to_str = unsafe { CStr::from_ptr(to_city).to_str().unwrap() };
// 调用Rust逻辑
let result = search_routes_impl(from_str, to_str);
CString::new(result).unwrap().into_raw()
}
#[no_mangle]
pub extern "C" fn free_string(ptr: *mut c_char) {
unsafe {
if ptr.is_null() { return; }
CString::from_raw(ptr);
}
}
```
## 科技优势
1. **性能**:C++核心算法提供高性能路径计算
2. **安全**:Rust处理数据管理和网络请求,内存安全
3. **跨平台**:Java覆盖Android,C++/Rust覆盖其他平台
4. **可维护**:模块化设计,职责分离清晰
这个设计充分利用了三种语言的优势,提供了高性能、安全可靠的铁路查询解决方案。