Eclipse Modeling Framework (EMF) 是 Eclipse 生態系中奠基性的模型驅動開發 (MDD) 框架。給定一個模型(XML Schema、UML 類別圖、或註解過的 Java 介面),EMF 能自動生成完整的 Java 實作程式碼,支援模型實例的建立、查詢、更新、序列化/反序列化、驗證與變更追蹤。更強大的是,EMF 提供動態反射 API,讓開發者無需生成程式碼即可在運行時操作模型。
EMF 的核心元模型稱為 Ecore,相當於 MOF (Meta-Object Facility) 的精簡 Java 實作。關鍵介面與類別:
EObject:所有模型物件的根介面,對應 java.lang.Object。提供 eClass() 取得元資料、eGet()/eSet() 反射存取、eContainer() 取得父容器、eAdapters() 變更通知機制。EPackage:模型命名空間容器,包含 EClass、EDataType。EClass:模型類別,定義 EAttribute(簡單屬性)與 EReference(關聯/引用)。EFactory:建立模型實例的工廠介面。適用於模型在開發期未知、或需處理多種異構模型的場景。以下以「公司-部門-員工」模型為例:
EcoreFactory ef = EcoreFactory.eINSTANCE;
EcorePackage ep = EcorePackage.eINSTANCE;
// Company 類別
EClass companyClass = ef.createEClass(); companyClass.setName("Company");
EAttribute companyName = ef.createEAttribute();
companyName.setName("name"); companyName.setEType(ep.getEString());
companyClass.getEStructuralFeatures().add(companyName);
// Employee 類別
EClass employeeClass = ef.createEClass(); employeeClass.setName("Employee");
EAttribute empName = ef.createEAttribute();
empName.setName("name"); empName.setEType(ep.getEString());
employeeClass.getEStructuralFeatures().add(empName);
// Department 類別
EClass deptClass = ef.createEClass(); deptClass.setName("Department");
EAttribute deptNum = ef.createEAttribute();
deptNum.setName("number"); deptNum.setEType(ep.getEInt());
deptClass.getEStructuralFeatures().add(deptNum);
// 關聯:Department 1..* 包含 Employee
EReference deptEmps = ef.createEReference();
deptEmps.setName("employees"); deptEmps.setEType(employeeClass);
deptEmps.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
deptEmps.setContainment(true);
deptClass.getEStructuralFeatures().add(deptEmps);
// 關聯:Company 1..* 包含 Department
EReference compDepts = ef.createEReference();
compDepts.setName("departments"); compDepts.setEType(deptClass);
compDepts.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
compDepts.setContainment(true);
companyClass.getEStructuralFeatures().add(compDepts);
// 封裝為 EPackage
EPackage companyPkg = ef.createEPackage();
companyPkg.setName("company"); companyPkg.setNsPrefix("company");
companyPkg.setNsURI("https://example.com/company");
companyPkg.getEClassifiers().addAll(Arrays.asList(employeeClass, deptClass, companyClass));
EFactory factory = companyPkg.getEFactoryInstance();
// 建立 Company 實例
EObject company = factory.create(companyClass);
company.eSet(companyName, "MyCompany");
// 建立 Employee、Department 並建立關聯
EObject emp = factory.create(employeeClass);
emp.eSet(empName, "John");
EObject dept = factory.create(deptClass);
dept.eSet(deptNum, 123);
((List) dept.eGet(deptEmps)).add(emp);
((List) company.eGet(compDepts)).add(dept);
EMF 使用 Resource 抽象儲存位置(檔案、URL),ResourceSet 管理多資源跨引用與載入去重。支援多種序列化格式(XMI、XML Schema 等)。
ResourceSet rs = new ResourceSetImpl();
Resource res = rs.createResource(URI.createFileURI("company.xmi"));
res.getContents().add(company);
res.save(null); // 序列化為 XMI
// 反序列化
Resource res2 = rs.getResource(URI.createFileURI("company.xmi"), true);
EObject loadedCompany = res2.getContents().get(0);
| 場景 | 建議模式 | 理由 |
|---|---|---|
| 模型在開發期固定、追求效能與型別安全 | 生成式 (GenModel → Java Code) | 記憶體較少、存取速度快、IDE 程式碼提示完整 |
| 模型運行時才確定、需處理多種外部 Schema、通用資料處理工具 | 動態模型 (Dynamic EMF) | 無需重新編譯、靈活適應結構變化、適合中介軟體/ETL |
EMF 是 Eclipse 眾多頂級專案的基石:XSD (XML Schema Infoset Model)、SDO (Service Data Objects)、UML2、WTP (Web Tools Platform)、GMF (Graphical Modeling Framework) 皆建構於 EMF 之上。商業產品如 IBM Rational、WebSphere、Omondo EclipseUML 亦深度依賴 EMF。
掌握 EMF,即掌握了 Eclipse 模型驅動開發的核心鑰匙。