利用Observer模式解决不同模块之间的交互

利用Observer模式解决不同模块之间的交互

 

最近在做一个基于NetBeans Platform技术的Java客户端应用。在该应用中,有一系列的窗口组件(TopComponent),每一个窗口组件位于一个NetBeans Module中。这些Module是相互独立的,不能互相引用。这些不同的Module里面的各种窗口组件之间可能有各种交互行为。

 

以下面的业务场景来举例说明:

在第一个ModuleWorkspaceModule中,有一个窗口组件WorkspaceTopComponent,双击打开其中的某一个Workspace(某种业务对象),就会引起另外两个Module中的若干窗口组件的变化:

在第二个ModuleDocumentModule中,窗口组件DocumentTopComponent会显示打开的Workspace下的Document(某种业务对象)列表;

在第三个ModuleJobModule中,窗口组件JobTopComponent会显示打开的Workspace下的Job(某种业务对象)列表。

等等诸如此类的交互行为。

 

一种做法是直接在WorkspaceModule中添加对DocumentModuleJobModule两个模块的引用,在WorkspaceTopComponent中直接操作DocumentTopComponentJobTopComponent,这种做法导致了这些模块之间的紧密耦合,失去了作为Module存在的意义。

 

Eclipse RCP中有一个比较爽的扩展点机制(Extension Point),可以用来轻松解决这种问题,在NetBeans中尚不清楚有没有类似的机制,因此采用Observer模式来尝试解决这种问题。

 

一、交互发起者和交互响应者接口

 

我们将发起交互的组件视为被观察者(Subject),对交互进行响应的组件视为观察者(Observer)。在标准JDK中已经提供了Observable类和Observer接口来提供这种机制,但是Observable是一个类,限制了它的使用。在我们的应用中,我们用下面两个接口来表示:

 

交互发起者接口ISponsor,它接受交互响应者的注册。

 

public interface ISponsor {

   

    void register(IResponsor r);

   

    void unregister(IResponsor r);

   

    void unregisterAll();

}

 

交互响应者接口IResponsor,它要向感兴趣的交互发起者注册。

public interface IResponsor {

       //这是一个标记接口,无方法

}

 

二、具体的交互发起者和具体的交互响应者接口

 

上面的两个接口是业务无关的,只提供了注册的机制,不涉及到具体的交互通知和响应。具体到业务,需要由具体的交互发起者和具体的交互响应者来提供。

在上面的业务场景中,WorkspaceTopComponent是一个具体的交互发起者,它会发起打开Workspace和关闭Workspace两种操作。为此提取出如下的接口:

public interface IWorkspaceSponsor extends ISponsor{

      

    void notifyWorkspaceOpened(Workspace ws);

   

    void notifyWorkspaceClosed(Workspace ws);

}

DocumentTopComponentJobTopComponent是上述两种操作的具体的交互响应者。为此提取出如下的接口:

public interface IWorkspaceResponsor extends IResponsor{

   

    void workspaceOpened(Workspace ws);

  

    void workspaceClosed(Workspace ws);

}

 

三、交互发起者注册表

 

在我们的应用中,可能有众多的交互发起者和交互响应者,各种交互响应者如何找到它所感兴趣的交互发起者,这是一个问题。我们提供一个交互发起者注册表(SponsorRegistry)的单实例对象来提供这种功能:

public class SponsorRegistry {

   

    private Map<String,ISponsor> smap=new HashMap<String,ISponsor>();

   

    private static SponsorRegistry registry=new SponsorRegistry();

   

    private SponsorRegistry() {

    }

   

    public static SponsorRegistry getRegistry(){

        return registry;

    }

   

    public void addSponsor(String sponsorName,ISponsor sponsor){

        smap.put(sponsorName,sponsor);

    }

   

    public void removeSponsor(String sponsorName){

        smap.remove(sponsorName);

    }

   

    public ISponsor getSponsor(String sponsorName){

        return smap.get(sponsorName);

    }

}

 

四、具体的交互发起者实现类和具体的交互响应者实现类

 

在上面的业务场景中,WorkspaceTopComponent实现IWorkspaceSponsor接口,并在组件创建时将自身注册到SponsorRegistry中。

//注:TopComponentNetBeans Platform中提供的一种窗口界面组件,它继承自JComponent,下面的代码中改为继承JComponent也应该没问题。

public class WorkspaceTopComponent extends TopComponent implements IWorkspaceSponsor{

    private List<IWorkspaceResponsor> responsors=new ArrayList<IWorkspaceResponsor>();

 

    //下面是实现 ISponsor接口和IWorkspaceSponsor接口的相关方法

    public synchronized void register(IResponsor r){

        if(r instanceof IWorkspaceResponsor){

            responsors.add((IWorkspaceResponsor)r);

        }

        else{

            //...

        }

    }

   

    public synchronized void unregister(IResponsor r){

        if(r instanceof IWorkspaceResponsor){

            responsors.remove((IWorkspaceResponsor)r);

        }

        else{

            //...

        }

    }

   

    public synchronized void unregisterAll(){

        responsors.clear();

    }

   

    public void notifyWorkspaceOpened(Workspace ws){

        synchronized(this){

            Iterator<IWorkspaceResponsor> it=responsors.iterator();

            while(it.hasNext())

                it.next().workspaceOpened(ws);

        }

    }

   

    public void notifyWorkspaceClosed(Workspace ws){

        synchronized(this){

            Iterator<IWorkspaceResponsor> it=responsors.iterator();

            while(it.hasNext())

                it.next().workspaceClosed(ws);

        }

    }

 

    //当窗口创建时,将自身注册到SponsorRegistry

    public void componentOpened() {

        SponsorRegistry.getRegistry().addSponsor("WorkspaceSponsor",this);

    }

   

    //其他界面和逻辑的实现代码略

    //....

}

 

DocumentTopComponentJobTopComponent均实现IWorkspaceResponsor接口,并在组件创建时从SponsorRegistry中找到名为WorkspaceSponsor的交互发起者,注册上去。

public class DocumentTopComponent extends TopComponent implements IWorkspaceSponsor{

 

    public void workspaceOpened(Workspace ws){

        //todo...

    }

   

    public void workspaceClosed(Workspace ws){

        //todo...

    }

 

    //当窗口创建时,找到Sponsor并注册上去

    public void componentOpened() {

        ISponsor s=SponsorRegistry.getRegistry().getSponsor("WorkspaceSponsor");

        s.register(this);

    }

   

    //当窗口关闭时,找到Sponsor并进行注销

    public void componentClosed() {

        ISponsor s=SponsorRegistry.getRegistry().getSponsor("WorkspaceSponsor");

        s.unregister(this);

    }

   

    //其他界面和逻辑的实现代码略

    //....

}

 

public class JobTopComponent extends TopComponent implements IWorkspaceSponsor{

 

    public void workspaceOpened(Workspace ws){

        //todo...

    }

   

    public void workspaceClosed(Workspace ws){

        //todo...

    }

 

    //当窗口创建时,找到Sponsor并注册上去

    public void componentOpened() {

        ISponsor s=SponsorRegistry.getRegistry().getSponsor("WorkspaceSponsor");

        s.register(this);

    }

   

    //当窗口关闭时,找到Sponsor并进行注销

    public void componentClosed() {

        ISponsor s=SponsorRegistry.getRegistry().getSponsor("WorkspaceSponsor");

        s.unregister(this);

    }

   

    //其他界面和逻辑的实现代码略

    //....

}

 

五、模块结构和依赖关系

 

根据以上的描述,上述业务场景现在由如下几个Module组成:

ObserverModule,提供交互发起者和交互响应者机制的的底层Module

ISponsor接口、IResponsor接口位于此Module中,

SponsorRegistry类也位于此Module中。

 

BusinessModule,管理各种具体的交互发起者接口和交互响应者接口的Module

IWorkspaceSponsor接口、IWorkspaceResponsor接口位于此Module中,

Workspace类等公共的业务对象也位于此Module中。

 

WorkspaceModuleWorkspace业务功能所在模块。

WorkspaceTopComponent位于此Module中。

 

DocumentModuleDocument业务功能所在模块。

DocumentTopComponent位于此Module中。

 

JobModuleJob业务功能所在模块。

JobTopComponent位于此Module中。

 

下图是以上模块的依赖关系示意图:

 

 

 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值