EMF 應用程式中,所有使用者操作皆透過命令執行,支援 Undo/Redo。命令框架分為兩層:
org.eclipse.emf.common.command):與模型無關,可用於任何需命令模式的場合。核心介面 Command 定義 execute()、undo()、redo() 等;CommandStack 管理命令歷史;CompoundCommand 提供事務性組合命令。org.eclipse.emf.edit.command):建立在通用命令之上,針對 EMF 模型編輯。常見有 SetCommand(修改屬性)、CreateChildCommand(建立子元素)、MoveCommand、CopyCommand 等。多繼承自 AbstractOverrideableCommand,擴充時需覆寫 doExecute()、doCanUndo() 等方法。需求:產品價格只保留小數點後兩位,且不得為負數。
public class SetPriceCommand extends SetCommand {
public SetPriceCommand(EditingDomain domain, EObject owner,
EStructuralFeature feature, Object value) {
super(domain, owner, feature, value);
}
@Override
protected void doExecute() {
Product product = (Product) owner;
double newPrice = ((Double) value).doubleValue();
newPrice = Math.max(0, newPrice); // 不小於 0
newPrice = Math.round(newPrice * 100) / 100.0; // 四捨五入至兩位小數
product.setPrice(newPrice);
}
}
@Override
protected Command createSetCommand(EditingDomain domain, EObject owner,
EStructuralFeature feature, Object value, int index) {
if (feature == ShopPackage.eINSTANCE.getProduct_Price()) {
return new SetPriceCommand(domain, owner, feature, value);
}
return super.createSetCommand(domain, owner, feature, value, index);
}
當使用者在屬性視圖修改價格時,即會使用自訂命令,自動套用業務規則。
CreateChildCommand 不繼承 AbstractOverrideableCommand,若需在建立子元素時自動初始化,應改在 XXXItemProvider 的 collectNewChildDescriptors() 中處理。
GEF 也有類似的 EditDomain 與 Command,但兩套機制未統一介面,結合使用時需額外轉接代碼。
透過自訂 .Edit 命令,可將業務驗證、資料轉換等邏輯封裝於命令層,保持模型純粹,同時完整支援 Undo/Redo,是 EMF 應用開發的關鍵技巧。