2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

GEF 框架中的設(shè)計(jì)模式

 gyb98 2010-12-11
邵 兵, 研究員, IBM 中國(guó)研究院
石 立川, 軟件工程師, IBM 中國(guó)研究院
王 晗, IBM 實(shí)習(xí)生, IBM 中國(guó)研究院

 

簡(jiǎn)介: 本文從設(shè)計(jì)模式的角度出發(fā),通過(guò)解析關(guān)鍵應(yīng)用場(chǎng)景,深層次地介紹了圖形編輯框架 (Graphical Editing Framework, GEF) 涉及的大量概念和技術(shù)。本文主要涉及 MVC、命令、工廠、觀察者、職責(zé)鏈、狀態(tài)等模式。通過(guò)本文,希望能夠幫助 Eclipse RCP 開發(fā)者更好地理解和應(yīng)用 GEF 這一框架。

發(fā)布日期: 2010 年 6 月 03 日
級(jí)別: 中級(jí)
訪問(wèn)情況 240 次瀏覽
建議: 0 (添加評(píng)論)

1 star2 stars3 stars4 stars5 stars 平均分 (共 6 個(gè)評(píng)分 )

前言

圖形編輯框架 (Graphical Editing Framework, GEF) ,是 Eclipse 平臺(tái)下一個(gè)重要的框架,用來(lái)從應(yīng)用模型開發(fā)富圖形化的編輯器,是 Eclipse RCP 開發(fā)者的神兵利器。 GEF 框架涉及大量的概念和技術(shù),有著非常陡峭的學(xué)習(xí)曲線。本文從設(shè)計(jì)模式的角度出發(fā),解析 GEF 框架中的關(guān)鍵應(yīng)用場(chǎng)景,希望能夠幫助 Eclipse RCP 開發(fā)者更好地理解和應(yīng)用這一框架。

GEF 通過(guò)大量使用設(shè)計(jì)模式來(lái)獲取它的靈活性。除了 MVC 模式,GEF 最經(jīng)常用到的設(shè)計(jì)模式是命令、工廠、觀察者、職責(zé)鏈和狀態(tài)。

  • 模型-視圖-控制器 (Model-View-Controller):MVC 模式被 GEF 用來(lái)解除用戶界面,行為和表示之間的耦合。模型可以用任意 Java 對(duì)象表示,EMF (Eclipse Modeling Framework,Eclipse 建??蚣?) 被普遍使用來(lái)構(gòu)造 GEF 的模型。視圖必須實(shí)現(xiàn) IFigure 接口,控制器則必須是 EditPart 類型。
  • 命令 (Command):用來(lái)封裝對(duì)模型的修改,支持 redo、undo 操作。
  • 工廠 (Factory): GEF 框架應(yīng)用工廠方法模式創(chuàng)建 Figure 應(yīng)用抽象工廠模式創(chuàng)建 EditPart。
  • 觀察者 (Observer):通過(guò)觀察 EditPart 的激活狀態(tài),ConnectionCreationTool 修改待創(chuàng)建連接的連接源。
  • 職責(zé)鏈 (Chain of Responsibility):用來(lái)決定請(qǐng)求 (Request) 如何被編輯策略 (EditPolicy) 處理。
  • 狀態(tài) (State):對(duì)于鍵盤、鼠標(biāo)輸入,GEF 編輯器通過(guò) Tool 的改變來(lái)改變自己的行為。

本文示例代碼來(lái)自于 GEF 的 3.4.1 版本。


模型-視圖-控制器 (Model-view-controller, MVC)

GEF 框架嚴(yán)格遵循模型-視圖-控制器模式 (MVC) 。


圖 1. GEF 中的模型-視圖-控制器 (images/gef_mvc_pattern.jpg)
圖 1. gef 中的模型-視圖-控制器 (images/gef_mvc_pattern.jpg)

GEF 中的模型可以是任意的數(shù)據(jù)。模型使用一種能在模型改變時(shí)通知控制器處理的事件通知機(jī)制。這種模型可以由手工來(lái)實(shí)現(xiàn),也可以通過(guò) EMF(Eclipse Modeling Framework) 自動(dòng)生成。而對(duì)模型的修改一般由 Command 來(lái)完成。

EditParViewer 是 GEF 中的展現(xiàn)視圖的地方。常見(jiàn)的 EditParViewer 有兩種: GraphicalViewer 和 TreeViewer。GraphicalViewer 主要依靠 Draw2d 中的 Figure 來(lái)完成的。開發(fā)人員可以通過(guò)實(shí)現(xiàn) IFigure 接口來(lái)完成復(fù)雜圖形的設(shè)計(jì)。對(duì)于 TreeViewer 而言,則由 SWT 中的 Tree 和 TreeItem 來(lái)完成視圖的繪制。

EditPart 對(duì)應(yīng) MVC 模式中的控制器,它維護(hù)著視圖與模型的對(duì)應(yīng)關(guān)系。在 AbstractGraphicalEditPart 中,createFigure 方法負(fù)責(zé)創(chuàng)建 Figure 圖形,refreshVisuals 方法負(fù)責(zé)對(duì) Figure 圖形進(jìn)行更新。一般情況下,模型與 EditPart 是一一對(duì)應(yīng)的。模型數(shù)據(jù)的更新由 EditPart 所安裝的編輯策略產(chǎn)生的 Command 來(lái)完成。GEF 框架中的常見(jiàn)的 EditPart 實(shí)現(xiàn)有三種,分別是 GraphicalEditPart,ConnecitonEditPart 和 TreeEditPart。


命令 (Command)

GEF 不會(huì)直接修改模型,而是要求使用命令來(lái)做實(shí)際的修改。通過(guò)命令,實(shí)現(xiàn)對(duì)模型或模型屬性的修改和撤銷。這樣,GEF 編輯器就自動(dòng)支持了模型修改的 undo/redo。

Command 類是 GEF 中的一個(gè)抽象類,主要實(shí)現(xiàn)如下幾個(gè)方法:

  • execute:這是命令的執(zhí)行方法,當(dāng)請(qǐng)求結(jié)束并獲得 Command 后,GEF 框架 ( 通過(guò) CommandStack) 負(fù)責(zé)執(zhí)行此方法。
  • undo:對(duì)模型修改后,可以通過(guò) undo 進(jìn)行撤銷。
  • redo:當(dāng)用戶撤銷后,能通過(guò) redo 重復(fù)上一次的操作。

圖 2. Command 相關(guān)類圖 (images/command.jpg)
圖 2. command 相關(guān)類圖 (images/command.jpg)

每個(gè)編輯策略都會(huì)為請(qǐng)求返回一個(gè)命令,不希望處理請(qǐng)求的策略將返回一個(gè) null。GEF 通過(guò)一個(gè)命令堆棧 (CommandStack) 執(zhí)行和保存 Command 對(duì)象。用戶通過(guò)命令堆棧可以輕松撤銷或重復(fù)對(duì)模型所做的操作。


工廠 (Factory)

工廠模式是用于將生成對(duì)象的步驟進(jìn)行封裝的創(chuàng)建型模式。常見(jiàn)的形態(tài)有以下幾種:

  1. 簡(jiǎn)單工廠 (Simple Factory):又叫做靜態(tài)工廠方法 (Static Factory Method) 模式,但不屬于 23 種 GOF 設(shè)計(jì)模式。簡(jiǎn)單工廠模式由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例。
  2. 工廠方法模式 (Factory Method):定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類。將創(chuàng)建工作推遲到工廠角色的子類去完成。
  3. 抽象工廠模式 (Abstract Factory):聲明一個(gè)抽象的工廠接口,工廠的多個(gè)子類分別創(chuàng)建某一系列的產(chǎn)品。

在 GEF 中,F(xiàn)igure 的創(chuàng)建應(yīng)用了工廠方法模式。抽象類 AbstractGraphicalEditPart 擔(dān)當(dāng)抽象工廠角色,定義了生成 Figure 的抽象方法 createFigure()。具體工廠角色則有 AbstractGraphicalEditPart 的子類擔(dān)當(dāng),負(fù)責(zé)生成具體的編輯器圖形。


圖 3. AbstractGraphicalEditPart 類圖 (images/factory_method.jpg)
圖 3. abstractgraphicaleditpart 類圖 (images/factory_method.jpg)

EditPart 實(shí)例對(duì)象的創(chuàng)建則運(yùn)用了抽象工廠模式。所有的 EditPart 均由 EditPartFactory 的子類負(fù)責(zé)創(chuàng)建,GEF 自身就提供了 RulerEditPartFactory 和 PaletteEditPartFactory 兩個(gè)工廠實(shí)現(xiàn)。如果用戶自定義 EditPart,必須提供相應(yīng)的 EditPartFactory 類型才能正確創(chuàng)建用戶的 EditPart 對(duì)象。


圖 4. EditPartFactory 相關(guān)類圖 (images/EditPartFactory.jpg)
圖 4. editpartfactory 相關(guān)類圖 (images/editpartfactory.jpg)

工廠方法和抽象工廠之間的區(qū)別在于,工廠方法模式只有一個(gè)抽象產(chǎn)品類,而抽象工廠模式有多個(gè)。工廠方法模式的具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例,而抽象工廠模式可以創(chuàng)建多個(gè)。


觀察者 (Observer)

觀察者模式是一種對(duì)象行為型模式,它可以定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)被依賴對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。

通過(guò)選項(xiàng)欄創(chuàng)建連接時(shí),ConnectionCreationTool 工具被生成用來(lái)創(chuàng)建連接,它通過(guò)監(jiān)聽(tīng)鼠標(biāo)的按下動(dòng)作來(lái)設(shè)置連接的連接源,在設(shè)置連接源時(shí),通過(guò) addEditPartListener 方法為源 EditPart 添加 deactivationListener 監(jiān)聽(tīng)。


清單 1. AbstractConnectionCreationTool 類中部分代碼
            package org.eclipse.gef.tools;
            public class AbstractConnectionCreationTool
            extends TargetingTool{
            ......
            private EditPartListener.Stub deactivationListener = new EditPartListener.Stub() {
            public void partDeactivated(EditPart editpart) {
            handleSourceDeactivated();
            }
            };
            protected boolean handleButtonDown(int button) {
            if (isInState(STATE_INITIAL) && button == 1) {
            updateTargetRequest();
            updateTargetUnderMouse();
            setConnectionSource(getTargetEditPart());
            Command command = getCommand();
            ((CreateConnectionRequest)getTargetRequest()).setSourceEditPart(
            getTargetEditPart());
            if (command != null) {
            setState(STATE_CONNECTION_STARTED);
            setCurrentCommand(command);
            viewer = getCurrentViewer();
            }
            }
            if (isInState(STATE_INITIAL) && button != 1) {
            setState(STATE_INVALID);
            handleInvalidInput();
            }
            return true;
            }
            protected void setConnectionSource(EditPart source) {
            if (connectionSource != null)
            connectionSource.removeEditPartListener(deactivationListener);
            connectionSource = source;
            if (connectionSource != null)
            connectionSource.addEditPartListener(deactivationListener);
            }
            protected void handleSourceDeactivated() {
            setState(STATE_INVALID);
            handleInvalidInput();
            handleFinished();
            }
            }
            

deactivationListener 是 EditPartListener.Stub 類型的實(shí)例,用來(lái)觀察源 EditPart 的狀態(tài)。當(dāng)源 EditPart 的狀態(tài)由激活變?yōu)榉羌せ顣r(shí),及時(shí)通知工具 ConnectionCreationTool 做出停止創(chuàng)建連接的工作。


清單 2. AbstractEditPart 類中部分代碼
            package org.eclipse.gef.editparts;
            public abstract class AbstractEditPart
            implements EditPart, RequestConstants, IAdaptable {
            ... ...
            protected void fireDeactivated() {
            Iterator listeners = getEventListeners(EditPartListener.class);
            while (listeners.hasNext())
            ((EditPartListener)listeners.next()).
            partDeactivated(this);
            }
            /**
            * Adds an EditPartListener.
            * @param listener the listener
            */
            public void addEditPartListener(EditPartListener listener) {
            eventListeners.addListener(EditPartListener.class, listener);
            }
            public void removeEditPartListener(EditPartListener listener) {
            eventListeners.removeListener(EditPartListener.class, listener);
            }
            }
            

在這個(gè)過(guò)程中,EditPart 成為被觀察的目標(biāo),提供了注冊(cè)和刪除觀察者對(duì)象的接口。EditPartListener.Stub 類型的實(shí)例 deactivationListener 扮演了觀察者的角色,在目標(biāo) EditPart 的狀態(tài)變成非激活時(shí),獲取更新并通知 ConnectionCreationTool 取消連接的創(chuàng)建。


職責(zé)鏈 (Chain of Responsibility)

職責(zé)鏈?zhǔn)且环N對(duì)象行為型模式。請(qǐng)求發(fā)出后,將在候選對(duì)象鏈 ( 職責(zé)鏈 ) 中進(jìn)行傳遞,并有滿足條件的對(duì)象進(jìn)行處理。職責(zé)鏈模式降低了請(qǐng)求的發(fā)送者和接收者之間的耦合度,允許在運(yùn)行時(shí)對(duì)職責(zé)鏈進(jìn)行動(dòng)態(tài)的增加或修改以增加或改變處 理請(qǐng)求的職責(zé)。關(guān)于職責(zé)鏈模式更詳細(xì)的描述,請(qǐng)參考 GOF 《設(shè)計(jì)模式》一書。

在 GEF 中,Tools 或者其他的 UI 解釋程序?qū)⒂脩舻木庉嫴僮鬓D(zhuǎn)換為一系列的請(qǐng)求 (Request),比如,用戶在選項(xiàng)板 (Palette) 里選擇了創(chuàng)建節(jié)點(diǎn)工具 (CreationTool),然后在畫布區(qū)域按下鼠標(biāo)左鍵,這時(shí)產(chǎn)生在畫布上的鼠標(biāo)單擊事件將被 CreationTool 轉(zhuǎn)換為一個(gè) CreateRequest,它里面包含了要?jiǎng)?chuàng)建的對(duì)象,坐標(biāo)位置等信息。

GEF 已經(jīng)為我們提供了很多種類的 Request,其中最常用的是 CreateRequest 及其子類 CreateConnectionRequest,下圖列出了 GEF 中已經(jīng)實(shí)現(xiàn)的 Request.


圖 5. Request 子類 (images/request_type_hierarchy.jpg)
圖 5. request 子類 (images/request_type_hierarchy.jpg)

Editparts 不能直接處理編輯操作產(chǎn)生的 Request,而是通過(guò)安裝的對(duì)應(yīng) EditPolicy 來(lái)處理。EditPolicy 的主要功能是根據(jù)請(qǐng)求創(chuàng)建相應(yīng)的命令 (Command),而后者會(huì)直接操作模型對(duì)象。每個(gè) EditPolicy 專注于一個(gè)單一的編輯任務(wù)或相關(guān)任務(wù)組,這使得一些編輯操作可以在不同 EditPart 實(shí)現(xiàn)共享。EditPolicies 決定了一個(gè) EditPart 的編輯能力。

EditPart 在創(chuàng)建時(shí),調(diào)用方法 createEditPolicies() 來(lái)安裝一些適用的編輯策略。在示例代碼中,ConnectionEditPart 安裝了兩個(gè) EditPolicy。第一個(gè)是 ConnectionComponentPolicy,它給 Delete 菜單項(xiàng)所需要的 action 提供刪除命令。第二個(gè)是 ConnectionEndpointEditPolicy,用來(lái)提供連接 (Connection) 轉(zhuǎn)移的策略。


清單 3. ConnectionEditPart 類中部分代碼
            class ConnectionEditPart extends AbstractConnectionEditPart
            implements PropertyChangeListener {
            ...
            protected void createEditPolicies() {
            installEditPolicy(EditPolicy.CONNECTION_ROLE, new ConnectionEditPolicy() {
            protected Command getDeleteCommand(GroupRequest request) {
            return new ConnectionDeleteCommand(getCastedModel());
            }
            });
            installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE,
            new ConnectionEndpointEditPolicy());
            }    ...
            }
            

請(qǐng)求提交到選定的 editpart 后,通過(guò) EditPolicy 的職責(zé)鏈進(jìn)行處理。從第一個(gè) EditPolicy 開始,鏈中收到請(qǐng)求的 EditPolicy 確定是否可以處理它,否則轉(zhuǎn)發(fā)給鏈中的下一個(gè) editpolicy。EditPolicy 的聲明順序決定了請(qǐng)求被傳遞的順序。多個(gè)編輯策略可以收到請(qǐng)求,返回 Commands 作為響應(yīng),這些 Commands 以鏈的方式組織在一起。示例代碼描述了 AbstractEditPart 中的職責(zé)鏈工作方式。


清單 4. AbstractEditPart 類中部分代碼
            package org.eclipse.gef.editparts;
            public abstract class AbstractEditPart
            implements EditPart, RequestConstants, IAdaptable
            {
            ......
            public Command getCommand(Request request) {
            Command command = null;
            EditPolicyIterator i = getEditPolicyIterator();
            while (i.hasNext()) {
            if (command != null)
            command = command.chain(i.next().getCommand(request));
            else
            command = i.next().getCommand(request);
            }
            return command;
            }
            }
            


狀態(tài) (State)

同職責(zé)鏈模式一樣,狀態(tài) (State) 也是一種對(duì)象行為型模式。狀態(tài)模式允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。上下文 (context) 把狀態(tài)相關(guān)的行為委托到狀態(tài)對(duì)象上。對(duì)象通過(guò)上下文引用不同的狀態(tài)對(duì)象,在運(yùn)行時(shí)根據(jù)狀態(tài)改變它的行為。關(guān)于狀態(tài)模式更詳細(xì)的描述,請(qǐng)參考 GOF 《設(shè)計(jì)模式》一書。

在 GEF 的編輯器中,用戶在選項(xiàng)板 (Palette) 切換工具可以改變編輯器的狀態(tài),從而修改編輯器的行為。例如,對(duì)于鼠標(biāo)按下事件,編輯器在激活選區(qū)工具和激活創(chuàng)建工具下的行為是截然不同的。現(xiàn)在,我們就 來(lái)看一下 GEF 編輯器是如何根據(jù)當(dāng)前選中的 Tool 來(lái)改變行為的。

在每個(gè) GEF 的 Editor 里,都需要有一個(gè) EditDomain 的存在。EditDomain 類似于 GraphicalEditor 的執(zhí)行上下文環(huán)境,維護(hù)著 GEF 中的命令棧、負(fù)責(zé)事件通知等。在 EditDomain 中,通過(guò) setActiveTool 可以設(shè)置當(dāng)前處于 Active 狀態(tài)的 Tool。

EditDomain 類維護(hù)一個(gè)表示鼠標(biāo)和鍵盤輸入的工具對(duì)象 ( 一個(gè) Tool 接口實(shí)現(xiàn)類的實(shí)例 )。EditDomain 類將所有與視圖輸入相關(guān)的請(qǐng)求委托給這個(gè)工具對(duì)象。EditDomain 類使用 Tool 接口實(shí)現(xiàn)類的實(shí)例來(lái)執(zhí)行特定于視圖輸入的操作。在狀態(tài)模式中,EditDomain 對(duì)應(yīng)上下文環(huán)境,工具 (Tool) 對(duì)應(yīng)狀態(tài)。一旦 Active Tool 改變,EditDomain 對(duì)象就會(huì)改變它所使用的工具對(duì)象。


圖 6. Tool 繼承層次圖 (images/tool_hierarchy.jpg)
圖 6. tool 繼承層次圖 (images/tool_hierarchy.jpg)

需要注意的是,上圖關(guān)于 Tool 的繼承層次部分并不是嚴(yán)格按照 GEF 框架進(jìn)行描述,本文作者為了描述方便做了某種程度的簡(jiǎn)化。具體層次請(qǐng)參考 GEF 框架代碼。

示例代碼描述了 EditDomain 是如何將與視圖輸入相關(guān)的請(qǐng)求委托給它的 Tool 實(shí)例 activeTool。


清單 5. EditDomain 類中部分代碼
            package org.eclipse.gef;
            public class EditDomain {
            ......
            private Tool activeTool;
            private void handlePaletteToolChanged() {
            PaletteViewer paletteViewer = getPaletteViewer();
            if (paletteViewer != null) {
            ToolEntry entry = paletteViewer.getActiveTool();
            if (entry != null)
            setActiveTool(entry.createTool());
            else
            setActiveTool(getDefaultTool());
            }
            }
            public void setActiveTool(Tool tool) {
            if (activeTool != null)
            activeTool.deactivate();
            activeTool = tool;
            if (activeTool != null) {
            activeTool.setEditDomain(this);
            activeTool.activate();
            }
            }
            }
            

工具會(huì)執(zhí)行某些操作,這些操作可能包括:

  • 要求 editparts 顯示或隱藏反饋
  • 從 editparts 獲得命令
  • 在命令棧執(zhí)行命令
  • 更新鼠標(biāo)光標(biāo)

后記

GEF 出現(xiàn)的模式遠(yuǎn)不止我們列出來(lái)的這么多。我們只是列出了對(duì) GEF 框架理解有幫助的一些模式。本文作者從事 Eclipse RCP 開發(fā)多年,通過(guò)這篇文章,希望能將在 GEF 中體會(huì)到的一些設(shè)計(jì)思想與大家分享。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多