QtCreator插件开发(三)——QtCreator架构

QtCreator插件开发(三)——QtCreator架构

一、QtCreator架构简介

QtCreator的核心就是一个插件加载器,其所有功能都是通过插件实现的。
QtCreator架构如下:

QtCreator的核心功能由Core Plugin (Core::ICore)实现。
插件管理器(ExtensionSystem::PluginManager)对插件协作提供了简单方式,允许插件为其他插件扩展提供钩子。
PluginManager负责插件的加载,管理,销毁等工作。Core插件是QtCreator最基础的插件,提供了向界面增加菜单等功能。
QtCreator的核心系统是由PluginManager和Core插件构成。PluginManager负责插件的管理工作,Core负责提供QtCreator的最小功能集合。PluginManager将Core当做普通插件进行加载。对于自定义插件,Core是一个基础功能库,使用Core可以扩展QtCreator的功能。
QtCreator的所有功能,全是由插件实现的,使用插件机制的优点是简化了顶层业务,即插件管理工作的逻辑,缺点是增加了加载插件的复杂度,由于Core插件需要被其他插件依赖,所以qtcreator在插件加载时就必须要考虑插件之间的依赖性。

二、插件模块

1、插件模块

最基本的插件是一个共享库,从开发者的角度,插件是一个模块。
插件模块的实现需要满足以下功能:
A、在一个类中实现ExtensionSystem::IPlugin接口。
B、使用Q_EXPORT_PLUGIN宏导出插件类。
C、提供一个pluginspec插件描述文件,用于描述插件的元信息。
D、向其它插件暴露一个或多个对象。
E、查找其它插件暴露出来的可用的一个或多个对象。
插件都需要继承IPlugin的接口,插件是由描述文件和继承IPlugin的类库组成。
描述文件内容如下:

<plugin name="DoNothing" version="1.0.0" compatVersion="2.8.1">
    <vendor>Scorpio.org</vendor>
    <copyright>(C) 2010-2011 Scorpio.org</copyright>
    <license>Do anything you want.</license>
    <description>A plugin that does nothing.</description>
    <url>http://www.scorpio.net</url>
    <dependencyList>
        <dependency name="Core" version="2.8.1"/>
    </dependencyList>
</plugin>

插件描述文件描述了插件的基本信息,用于被插件管理器加载。最后一行描述了插件所依赖的其它插件,PluginManager会根据插件之间的依赖关系决定加载顺序。
IPlugin是插件的基类接口,主要接口如下:

//初始化函数,在插件被加载时会调用
bool IPlugin::initialize(const QStringList &arguments, QString *errorString)
//在所有插件的initialize函数被调用后,调用该函数,此时该插件依赖的插件已经初始化完成
void IPlugin::extensionsInitialized()
//在所有插件的extensionsInitialized函数调用完成以后进行调用
bool IPlugin::delayedInitialize()

2、暴露对象

暴露对象是存在于插件管理器对象池中的对象。
插件暴露出的对象会加入到PluginManager的对象池。PluginManager的allObjects()函数用于获取对象池中所有QObject对象的指针列表。下面的代码演示了如何在QListWidget组件中列出对象池中所有的对象:

#include <extensionsystem/pluginmanager.h>

ExtensionSystem::PluginManager* pm
         = ExtensionSystem::PluginManager::instance();

QList<QObject*> objects = pm->allObjects();
QListWidget* listWidget = new QListWidget;

Q_FOREACH(QObject* obj, objects)
{
    QString objInfo = QString("%1 (%2)")
                      .arg(obj->objectName())
                      .arg(obj->metaObject()->className());
    listWidget->addItem(objInfo);
}

将DoNothing插件中doNothing函数修改如下:

#include <extensionsystem/pluginmanager.h>

void DoNothingPlugin::doNothing()
{
    ExtensionSystem::PluginManager* pm
            = ExtensionSystem::PluginManager::instance();

    QList<QObject*> objects = pm->allObjects();
    QListWidget* listWidget = new QListWidget();
    Q_FOREACH(QObject* obj, objects)
    {
        QString objInfo = QString(QString::fromUtf8("%1 (%2)"))
                .arg(obj->objectName())
                .arg(QString::fromUtf8(obj->metaObject()->className()));
        listWidget->addItem(objInfo);
    }
    listWidget->resize(300,600);
    listWidget->show();
}


一个对外暴露的对象是由一个插件对外暴露的QObject(或其子类)的实例,暴露对象存在于对象池中,并且可供其它插件使用。

3、如何从插件中暴露对象

有三种方法从插件中暴露一个对象:
A、IPlugin::addAutoReleasedObject(QObject)
B、IPlugin::addObject(QObject
)
C、PluginManager::addObject(QObject)
IPlugin::addObject()和IPlugin::addAutoReleasedObject()其实都是调用的PluginManager::addObject()函数。建议使用IPlugin的函数添加对象。addAutoReleasedObject()和addObject()的唯一区别是,前者添加的对象会在插件销毁的时候自动按照注册顺序的反向顺序从对象池中移除并delete。
在任意时刻,都可以使用IPlugin::removeObject(QObject
)函数将对象从对象池中移除。

4、需要暴露的对象

插件可以暴露任何对象。通常,被其它插件使用了某些功能的对象会被暴露。QtCreator中,功能通过接口的方式定义。
下面是其中一些接口:
Core::INavigationWidgetFactory
Core::IEditor
Core::IOptionsPage
Core::IOutputPane
Core::IWizard
如果一个插件包含实现了接口的对象,那么这个对象就应该被暴露出来。例如,一个插件中的某个类实现了INavigationWidgetFactory接口,并且暴露出来,那么Core就会自动把这个类提供的组件当做导航组件显示出来。创建一个导航栏插件TableNav,通过实现?Core::INavigationWidgetFactory接口,将一个简单的QTableWidget当做导航组件。
Core::INavigationWidgetFactory接口实现如下:
NavWidgetFactory.h文件:

#ifndef NAVWIDGETFACTORY_H
#define NAVWIDGETFACTORY_H

#include <coreplugin/inavigationwidgetfactory.h>
#include <coreplugin/id.h>
using namespace Core;

class NavWidgetFactory : public Core::INavigationWidgetFactory
{
public:
    NavWidgetFactory();
    ~NavWidgetFactory();
    Core::NavigationView createWidget();
    QString displayName() const;
    int priority() const;
    Id id() const;
};

#endif // NAVWIDGETFACTORY_H

NavWidgetFactory.cpp文件:

#include "NavWidgetFactory.h"

#include <QtGui>

NavWidgetFactory::NavWidgetFactory() { }

NavWidgetFactory::~NavWidgetFactory() { }

Core::NavigationView NavWidgetFactory::createWidget()
{
    Core::NavigationView view;
    view.widget = new QTableWidget(50, 3);
    return view;
}

QString NavWidgetFactory::displayName() const
{
    return QString::fromUtf8("TableNav");
}

int NavWidgetFactory::priority() const
{
    return 0;
}

Id NavWidgetFactory::id() const
{
    return Id::fromName("TableNav");
}

TableNav插件实现如下:
TableNavPlugin .h文件:

#ifndef TABLENAVPLUGIN_H
#define TABLENAVPLUGIN_H

#include <extensionsystem/iplugin.h>
#include "NavWidgetFactory.h"

#include <QtPlugin>
#include <QtGui>

class TableNavPlugin : public ExtensionSystem::IPlugin
{
public:
    TableNavPlugin();
    ~TableNavPlugin();
    void extensionsInitialized();
    bool initialize(const QStringList & arguments, QString * errorString);
    void shutdown();
};

#endif // TABLENAVPLUGIN_H

TableNavPlugin .cpp文件:

#include "TableNavPlugin.h"
#include "NavWidgetFactory.h"

#include <QtPlugin>
#include <QtGui>

TableNavPlugin::TableNavPlugin()
{
    // Do nothing
}

TableNavPlugin::~TableNavPlugin()
{
    // Do notning
}

bool TableNavPlugin::initialize(const QStringList& args, QString *errMsg)
{
    Q_UNUSED(args);
    Q_UNUSED(errMsg);
    // Provide a navigation widget factory.
    // Qt Creator’s navigation widget will automatically
    // hook to our INavigationWidgetFactory implementation, which
    // is the NavWidgetFactory class, and show the QTableWidget
    // created by it in the navigation panel.
    //暴露对象
    addAutoReleasedObject(new NavWidgetFactory);
    return true;
}

void TableNavPlugin::extensionsInitialized()
{
    // Do nothing
}

void TableNavPlugin::shutdown()
{
    // Do nothing
}

Q_EXPORT_PLUGIN(TableNavPlugin)

TableNav插件描述文件如下:

<plugin name="TableNav" version="0.0.1" compatVersion="2.8.1">
    <vendor>Scorpio</vendor>
    <copyright>(C) 2010-2011 Scorpio.org</copyright>
    <license>MIT</license>
    <description>Table widget as navigation.</description>
    <url>http://www.scorpio.net</url>
    <dependencyList>
        <dependency name="Core" version="2.8.1"/>
    </dependencyList>
</plugin>

TableNav插件依赖文件如下:

QTC_PLUGIN_NAME = TableNav

QTC_PLUGIN_DEPENDS +=     coreplugin

TableNav插件工程文件如下:

EMPLATE = lib
TARGET = TableNav
include(../../qtcreatorplugin.pri)
PROVIDER = Scorpio
include(../../plugins/coreplugin/coreplugin.pri)

HEADERS += TableNavPlugin.h     NavWidgetFactory.h

SOURCES += TableNavPlugin.cpp     NavWidgetFactory.cpp

OTHER_FILES += TableNav.pluginspec     TableNav_dependencies.pri

结果如下:

5、监控暴露对象

当使用PluginManager::addObject()添加对象时,PluginManager就会发出objectAdded(QObject)信号。应用程序可以使用objectAdded(QObject)信号来弄清楚被添加的对象。
只有插件被初始化后,插件管理器才会发出objectAdded(QObject*)信号。只有被初始化后添加到插件管理器对象池的插件对象,才能收到objectAdded()信号。
通常,连接到objectAdded()信号的slot会寻找一个或多个已知接口。假设插件要找的是INavigationWidgetFactory接口,那么连接objectAdded()信号的槽函数如下:

void xxxPlugin::slotObjectAdded(QObject * obj)
{
    INavigationWidgetFactory *factory = Aggregation::query(obj);
    if(factory)
    {
        // use it here...
    }
}

6、查找对象

有时,插件需要在应用程序中查找提供了某些功能的对象。目前,已知查找对象的方法有两种:
A、PluginManager::allObjects()函数返回一个QList<QObject*>形式的对象池。
B、通过连接PluginManager::objectAdded()信号,可以知道被暴露的对象。
假设需要查找一个实现了INavigationWidgetFactory接口的对象,然后把它添加到一个QListWidget中显示出来。那么,可以使用PluginManager::getObjects<T>()函数。下面是代码片段:

ExtensionSystem::PluginManager* pm =                            ExtensionSystem::PluginManager::instance();
QList<Core::INavigationWidgetFactory*> objects
  = pm->getObjects<Core::INavigationWidgetFactory>();
QListWidget* listWidget = new QListWidget();
Q_FOREACH(Core::INavigationWidgetFactory* obj, objects)
{
    QString objInfo = QString("%1 (%2)")
                        .arg(obj->displayName())
                        .arg(obj->metaObject()->className());
    listWidget->addItem(objInfo);
}

三、Core插件

1、Core插件简介

QtCreator的核心系统由PluginManager和Core插件构成。PluginManager负责插件的管理工作,将Core插件当做普通插件进行加载;Core插件负责提供QtCreator的最小功能集合,为其它插件提供基础功能。
QtCreator所有功能由插件实现,优点是简化了顶层业务,即插件管理工作的逻辑,只有PlunginManager和Plugin;缺点是增加了加载插件的复杂度,因为Core基础库插件需要被其他插件依赖,所以QtCreator在插件加载时就必须要考虑插件之间的依赖性。
只包括core、Find、Locator、TextEditor四个必须插件的QtCreator界面如下:

2、Core插件的功能接口集合

C++?开发者通常会将只包含?public纯虚函数的类当做接口。在QtCreator中,接口则是拥有一个或多个纯虚函数的QObject子类。如果一个插件实现了IXXX接口的对象,那么这个对象就应该被暴露出来。例如,一个插件中的某个类实现了INavigationWidgetFactory接口,并且暴露出来,那么 Core 就会自动把这个类提供的组件当做导航组件显示出来。
QtCreator中,功能通过接口的方式定义。Core插件模块定义了QtCreator的常用功能接口集合,如下:
Core::IOptionsPage
Core::IWizard
Core::IEditor
Core::IEditorFactory
Core::IDocumentFactory
Core::IExternalEditor
Core::IContext
Core::ICore
Core::ICoreListener
Core::IDocument
Core::IFileWizardExtension
Core::IMode
Core::INavigationWidgetFactory
Core::IOutputPane
Core::IVersionControl
功能接口会在其它插件或Core插件实现,如git插件在GitVersionControl类对Core::IVersionControl接口进行了实现,Core插件在TextDocument类中对IDocument接口进行了实现。

3、Core插件的源码

coreplugin.h文件:

#ifndef COREPLUGIN_H
#define COREPLUGIN_H

#include <extensionsystem/iplugin.h>

namespace Core {
class DesignMode;
namespace Internal {

class EditMode;
class MainWindow;

class CorePlugin : public ExtensionSystem::IPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Core.json")

public:
    CorePlugin();
    ~CorePlugin();

    //必须实现接口initialize
    bool initialize(const QStringList &arguments, QString *errorMessage = 0);
    //必须实现接口extensionsInitialized
    void extensionsInitialized();
    bool delayedInitialize();
    ShutdownFlag aboutToShutdown();
    QObject *remoteCommand(const QStringList & /* options */, const QStringList &args);

public slots:
    void fileOpenRequest(const QString&);

private:
    void parseArguments(const QStringList & arguments);

    MainWindow *m_mainWindow;//主窗口
    EditMode *m_editMode;//编辑模式
    DesignMode *m_designMode;//设计器模式
};

} // namespace Internal
} // namespace Core

#endif // COREPLUGIN_H

coreplugin.cpp文件:

#include "coreplugin.h"
#include "actionmanager.h"
#include "designmode.h"
#include "editmode.h"
#include "editormanager.h"
#include "fileiconprovider.h"
#include "helpmanager.h"
#include "mainwindow.h"
#include "mimedatabase.h"
#include "modemanager.h"
#include "infobar.h"

#include <utils/savefile.h>

#include <QtPlugin>
#include <QDebug>
#include <QDateTime>

using namespace Core;
using namespace Core::Internal;

CorePlugin::CorePlugin() :
    m_mainWindow(new MainWindow), m_editMode(0), m_designMode(0)
{
}

CorePlugin::~CorePlugin()
{
    if (m_editMode) {
        removeObject(m_editMode);
        delete m_editMode;
    }

    if (m_designMode) {
        if (m_designMode->designModeIsRequired())
            removeObject(m_designMode);
        delete m_designMode;
    }

    // delete FileIconProvider singleton
    delete FileIconProvider::instance();

    delete m_mainWindow;
}

void CorePlugin::parseArguments(const QStringList &arguments)
{
    for (int i = 0; i < arguments.size(); ++i) {
        if (arguments.at(i) == QLatin1String("-color")) {
            const QString colorcode(arguments.at(i + 1));
            m_mainWindow->setOverrideColor(QColor(colorcode));
            i++; // skip the argument
        }
        if (arguments.at(i) == QLatin1String("-presentationMode"))
            ActionManager::setPresentationModeEnabled(true);
    }
}

bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
    qsrand(QDateTime::currentDateTime().toTime_t());
    parseArguments(arguments);
    const bool success = m_mainWindow->init(errorMessage);
    if (success) {
        m_editMode = new EditMode;
        addObject(m_editMode);
        //切换到编辑模式
        ModeManager::activateMode(m_editMode->id());
        m_designMode = new DesignMode;
        InfoBar::initializeGloballySuppressed();
    }

    // Make sure we respect the process‘s umask when creating new files
    Utils::SaveFile::initializeUmask();

    return success;
}

void CorePlugin::extensionsInitialized()
{
    m_mainWindow->mimeDatabase()->syncUserModifiedMimeTypes();
    if (m_designMode->designModeIsRequired())
        addObject(m_designMode);
    m_mainWindow->extensionsInitialized();
}

bool CorePlugin::delayedInitialize()
{
    HelpManager::instance()->setupHelpManager();
    return true;
}

QObject *CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args)
{
    IDocument *res = m_mainWindow->openFiles(
                args, ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineNumbers));
    m_mainWindow->raiseWindow();
    return res;
}

void CorePlugin::fileOpenRequest(const QString &f)
{
    remoteCommand(QStringList(), QStringList(f));
}

ExtensionSystem::IPlugin::ShutdownFlag CorePlugin::aboutToShutdown()
{
    m_mainWindow->aboutToShutdown();
    return SynchronousShutdown;
}

Q_EXPORT_PLUGIN(CorePlugin)
Core插件对Core::IMode进行了不同实现,如EditMode、DesignMode,并在initialize函数加载了相应功能。

四、插件与核心系统的通信

1、核心系统如何加载插件

在main函数中由ExtensionSystem::PluginManager插件管理器加载。
pluginManager.loadPlugins();
void PluginManager::loadPlugins()函数调用了void PluginManagerPrivate::loadPlugins()函数。

void PluginManagerPrivate::loadPlugins()
{
    //获取待加载的插件,loadQueue根据插件批次依赖关系进行排序
    QList<PluginSpec *> queue = loadQueue();
    //加载插件
    foreach (PluginSpec *spec, queue) {
        loadPlugin(spec, PluginSpec::Loaded);
    }
    //初始化插件
    foreach (PluginSpec *spec, queue) {
        loadPlugin(spec, PluginSpec::Initialized);
    }
    QListIterator<PluginSpec *> it(queue);
    it.toBack();
    while (it.hasPrevious()) {
        loadPlugin(it.previous(), PluginSpec::Running);
    }
    emit q->pluginsChanged();
}

2、插件如何使用核心系统为软件扩展功能

自定义插件使用Core插件提供的功能向界面添加菜单代码如下:

bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg)
{
    Q_UNUSED(args);
    Q_UNUSED(errMsg);

    Core::ActionManager* am = Core::ICore::instance()->actionManager();

    // Create a DoNothing menu
    Core::ActionContainer* ac = am->createMenu("DoNothingPlugin.DoNothingMenu");
    ac->menu()->setTitle(QString::fromUtf8("DoNothing"));
    // Create a command for "About DoNothing".
    Core::Command* cmd = am->registerAction(
                new QAction(this),
                "DoNothingPlugin.AboutDoNothing",
                Core::Context(Core::Constants::C_GLOBAL));
    cmd->action()->setText(QString::fromUtf8("About DoNothing"));
    connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(doNothing()));
    // Insert the "DoNothing" menu between "Window" and "Help".
    QMenu* helpMenu = am->actionContainer(Core::Constants::M_HELP)->menu();
    QMenuBar* menuBar = am->actionContainer(Core::Constants::MENU_BAR)->menuBar();
    menuBar->insertMenu(helpMenu->menuAction(), ac->menu());
    // Add the "About DoNothing" action to the DoNothing menu
    ac->addAction(cmd);

    return true;
}

DoNothing插件在initialize函数中使用Core插件的Core::ActionManager、Core::ActionContainer、Core::Command功能向主界面菜单栏添加菜单。

Git插件使用Core插件提供的功能向主界面菜单栏的git菜单提供菜单和菜单项,代码如下:

//register actions
    Core::ActionContainer *toolsContainer =
        Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);

    Core::ActionContainer *gitContainer = Core::ActionManager::createMenu("Git");
    gitContainer->menu()->setTitle(tr("&Git"));
    toolsContainer->addMenu(gitContainer);
    m_menuAction = gitContainer->menu()->menuAction();

    /*  "Current File" menu */
    Core::ActionContainer *currentFileMenu = Core::ActionManager::createMenu(Core::Id("Git.CurrentFileMenu"));
    currentFileMenu->menu()->setTitle(tr("Current &File"));
    gitContainer->addMenu(currentFileMenu);

五、聚合实现

聚合由Aggregation命名空间提供,提供了一种将不同类型的QObject粘合在一起的能力,因此可以将不同类型对象相互转换。使用Aggregation命名空间中的类和函数,就可以绑定相关对象到一个单独实体(聚合)。被绑定到聚合中的对象能够从聚合转换为不同的对象类类型。

1、聚合的传统实现

如果想要一个对象提供两个接口的实现,实现代码如下:

class Interface1
{
    ....
};
Q_DECLARE_INTERFACE("Interface1", "Interface1");

class Interface2
{
    ....
};
Q_DECLARE_INTERFACE("Interface2", "Interface2");

class Bundle : public QObject,
               public Interface1,
               public Interface2
{
    Q_OBJECT
    Q_INTERFACES(Interface1 Interface2)
    ....
};

Bundle bundle;

对象bundle同时实现了Interface1和Interface2。可以使用类型转换运算符,将bundle转换成Interface1或者Interface2:

Interface1* iface1Ptr = qobject_cast<Interface1*>(&bundle);
Interface2* iface2Ptr = qobject_cast<Interface2*>(&bundle);

2、QtCreator实现方式

QtCreator的Aggregation库提供了一种更加简洁的方式,来定义接口,然后将其打包成一个对象。创建Aggregation::Aggregate实例,然后将对象添加进该对象。加入聚合的每一个对象都可以实现一个接口。下面的代码显示了如何创建聚合。

#include <aggregation/aggregate.h>

class Interface1 : public QObject
{
    Q_OBJECT
public:
    Interface1() { }
    ~Interface1() { }
};

class Interface2 : public QObject
{
    Q_OBJECT
public:
    Interface2() { }
    ~Interface2() { }
};

Aggregation::Aggregate bundle;
bundle.add(new Interface1);
bundle.add(new Interface2);

聚合实例bundle现在有两个接口的实现。如果需要转换成相应接口,可以使用如下代码:

Interface1* iface1Ptr = Aggregation::query<Interface1>(&bundle);
Interface2* iface2Ptr = Aggregation::query<Interface2>(&bundle);
利用聚合,可以多次添加具有相同接口的多个对象。例如:
Aggregation::Aggregate bundle;
bundle.add(new Interface1);
bundle.add(new Interface2);
bundle.add(new Interface1);
bundle.add(new Interface1);
QList<Interface1*>gt; iface1Ptrs =      Aggregation::query_all<Interface1>(&bundle);

使用Aggregation的另一优点是,delete聚合中的任一对象,都可以将整个聚合delete掉。例如:

Aggregation::Aggregate* bundle = new Aggregation::Aggregate;
bundle->add(new Interface1);
bundle->add(new Interface2);

Interface1* iface1Ptr = Aggregation::query(bundle);
delete iface1Ptr;
// 同时会 delete 这个 bundle 及其中所有对象
// 等价于 delete bundle

原文地址:http://blog.51cto.com/9291927/2105705

时间: 2024-10-04 01:40:08

QtCreator插件开发(三)——QtCreator架构的相关文章

QtCreator插件开发(二)——QtCreator菜单和菜单项

QtCreator插件开发(二)--QtCreator菜单和菜单项 一.QtCreator菜单栏简介 1.QtCreator菜单简介 QtCreator菜单栏如下:QtCreator默认菜单包括"文件"."编辑"."工具"."窗体"."帮助"."构建"."调试"."分析"由插件提供,不是QtCreator的默认菜单.在"帮助"菜

QtCreator插件开发(一)——QtCreator插件实例

QtCreator插件开发(一)--QtCreator插件实例 版权声明:本系列文章翻译自:Writing Qt Creator Plugins.如果任何人或机构对于版权有异议,请联系我.本文将使用QtCreator-2.8.1版本进行插件开发,由于QtCreator-2.8.1的插件机制进行了部分更改,因此将根据QtCreator-2.8.1插件机制为基础撰写本文. 一.QtCreator源码编译 1.构建目录的创建 QtCreator工程的源码编译推荐在独立工作目录进行,避免源码被污染.在Q

Flex入门(三)——微架构之Cairngorm

大家都知道我们在开发后台的时候,都会使用MVC,三层等分层架构,使后台代码达到职责更为分明单一,高内聚低耦合,例如,Dao层只是进行和数据库打交道,负责处理数据:Service(B层)只是进行逻辑判断处理,而Action则进行后台和前台页面的交互等.从而使程序更加容易管理,更加灵活,更加容易扩展,更加容易维护.也就是大家比较熟悉的Struts(SpringMVC)+Spring+Hibernate(Mybatis)等. 而作为前台Flex处理,也提供了类似的处理功能,想要达到的效果,也是代码分层

系统架构师秘籍(三)架构视角和关注点

上次的博文中,我们介绍了一下软件架构的基本概念,接下来我们介绍一下如何来架构一个软件系统. 当我们开始进行系统架构设计的时候,通常会考虑以下几点: 所设计的软件体系结构的主要功能要素是什么. 如何将这些要素与其他系统关联. 哪些信息需要存储.管理和展示. 要实现这些功能要素需要什么硬件和软件. 所设计的软件体系结构提供什么样的特性和能力. 开发.测试.支持.培训环境都需要做什么. 考虑上述问题的时候,我们从哪些层面来考虑呢?那就是架构视角和关注点两个层面. 架构视角 架构视角是从一个或多个角度对

企业级应用框架(三)三层架构之数据访问层的改进以及测试DOM的发布

在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.net,EF,linq To Sql,这一点我们实现的不是很完美,仍有很大的改进空间,本文将加以改进. 在此之前我们来看一下我们最新的dom(PS:经过两天的赶工,我们的dom已经相对成熟,其中BLL层已经被我高度抽象化了,并且引进了业务上文文的概念:DAL层除了具体的技术实现尚为完成,其他方面已经相

阿里Java开发工程师理解的三种架构模型

常用的软件架构模型可以归类为三种架构模型:3/N层架构."框架+插件"架构.地域分布式架构. 一.三种架构模型 1.3/N层架构 这是经典的多层架构模型,对于稍微复杂一点或特别复杂的系统,不使用分层架构是很难想象的.下图是经典的3层架构: 如今,凡是个程序员都能侃侃而谈3/N层架构,这确实是解决系统复杂性的一种主流模式,但是,只要采用了3/N层架构是不是就一定能解决系统的复杂性了?不一定,关键在于你在你的系统中如何实作你的3/N层结构. 在采用了3/N层架构后,我们还是要解决以下非常重

朱晔的互联网架构实践心得S1E7:三十种架构设计模式(上)

朱晔的互联网架构实践心得S1E7:三十种架构设计模式(上) [下载本文PDF进行阅读] 设计模式是前人通过大量的实践总结出来的一些经验总结和最佳实践.在经过多年的软件开发实践之后,回过头来去看23种设计模式你会发现很多平时写代码的套路和OO的套路和设计模式里总结的类似,这也说明了你悟到的东西和别人悟到的一样,经过大量实践总能趋向性得出一些最佳实践的结论.架构设计也是一样,这里结合自己的理解分析一下微软给出的云架构的一些模式.话说微软干这方面的事情真的很厉害,之前翻译过的<微软应用架构指南>写的

Shuttle ESB(三)——架构模型介绍(2)

上一篇文章中,介绍了Shuttle ESB架构模型中的三个重要部分.今天,我们继续介绍剩余的三个内容:模式和消息路由. 四.模式 Request/Response(请求/响应模式) 对基于Request/Response消息机制的内容,你可以看WiKi的一些文章:http://en.wikipedia.org/wiki/Request-response 向一个终端发送请求,执行某项功能,你可以发送一个命令消息: bus.Send(new RequestMessage()); 虽然这是一个非常简单

jquery插件开发三种方法

1.好像之前看视频记录下来的,不记得了. 1 //类级别插件开发,主要是在jQuery中定义全局方法: 2 3 //第一种写法 4 jQuery.myFunc = function(str){ 5 alert("直接在jquery中定义方法",str) 6 } 7 //调用方式 $.myFunc("hello!"); 8 9 //第二种写法 10 jQuery.extend({ 11 myFunc:function(str){ 12 alert("exte