本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。
应用架构
CrossFly 不强制任何架构,也没有 DI 和响应式绑定(参见 状态与数据流)。这既是自由——也是责任。下面是建议采用(兼容而非强制)的、可扩展的约定。这是第 32 章的任务型摘选。
建议的包结构
app/
├─ ui/screens/ → uma tela = uma subclasse de Window
├─ viewmodel/ → estado + lógica de apresentação por tela
├─ data/repository → fachada sobre dev.crossfly.sqlite / rede
└─ service/ → serviços de app (singletons) + service locator
一个屏幕 = 一个 Window
public class ClientesScreen extends Window {
private final ClientesVM vm = new ClientesVM(Services.get(ClienteRepository.class));
@Override public void onShow() throws Exception {
super.onShow(); // 在此构建 UI(bounds 有效)
// … 连接 UI ↔ vm …
vm.observe(this::render); // 状态变化时重新渲染
vm.carregar();
}
@Override public void onRemove() { vm.dispose(); super.onRemove(); } // 释放资源
}
轻量的 ViewModel(不含 setState)
由于没有响应式绑定,ViewModel 保存状态并暴露一个 observe(Runnable);View 手动重新渲染:
public class ClientesVM {
private final ClienteRepository repo;
private Runnable onChange;
public List<Cliente> clientes = List.of();
public ClientesVM(ClienteRepository repo) { this.repo = repo; }
public void observe(Runnable r) { this.onChange = r; }
public void carregar() {
new Thread(() -> {
List<Cliente> dados = repo.listar();
Component.onUI(() -> { clientes = dados; if (onChange != null) onChange.run(); });
}).start();
}
public void dispose() { onChange = null; }
}
基于 SQLite 的 Repository
将数据访问隔离在一个门面中——UI 永远不直接讲 SQL:
public class ClienteRepository {
public List<Cliente> listar() {
try (SqliteDb db = SqliteDb.open("app.db");
SqliteCursor c = db.query("SELECT id, nome FROM cliente")) {
List<Cliente> out = new ArrayList<>();
while (c.next()) out.add(new Cliente(c.getLong(0), c.getString(1)));
return out;
}
}
}
用简单的服务定位器代替 DI
旧的 Registry 已被移除。用你自己的 Map<Class,Object> 来解析(或通过构造函数注入):
public final class Services {
private static final Map<Class<?>, Object> reg = new HashMap<>();
public static <T> void put(Class<T> k, T v) { reg.put(k, v); }
public static <T> T get(Class<T> k) { return k.cast(reg.get(k)); }
}
// 在 bootstrap 中:Services.put(ClienteRepository.class, new ClienteRepository());
最佳实践
- 在
onShow()中构建 UI,在onRemove()中释放资源。 - 状态放在 ViewModel 中;变更通过
onUI回到绘制线程;View 将状态转换为组件。 - Repository 隐藏 SQLite/网络;屏幕不了解 SQL。
常见错误
- 寻找 Flutter 那样的 DI/可观察对象——它们并不存在;使用服务定位器 + 手动
observe(...)。 - 把 SQL/HTTP 直接放进
Window(造成耦合并阻塞 UI)。 - 将应用状态保存在
Window的字段中(导航时会丢失)。
另请参阅
这个页面有帮助吗?感谢你的反馈!