简体   繁体   English

关于MVC视图界面的良好设计实践

[英]Good design practice concerning MVC view interface

I don't often have to create GUI's but today I do so I was hoping for some design input. 我不经常创建GUI,但今天我这样做,我希望有一些设计输入。

Basically I have a backend which I intend to add a GUI too using the MVC pattern. 基本上我有一个后端,我打算使用MVC模式添加一个GUI。 The issue is I feel whatever class encapsulates the main GUI window is going to have A LOT of state (all of the sub elements); 问题是我觉得无论什么类封装主GUI窗口都会有很多状态(所有的子元素); and on top of that it's going to have a lot of setters, and possibly getter, clear, colour, size, position and refresh functions too. 最重要的是,它将有很多制定者,可能还有吸气剂,清晰度,颜色,尺寸,位置和刷新功能。

  • One option is to march ahead with this idea and have a very large public interface which deals with the types the GUI uses ( std::string , std::vector<std::string> ...) the more control I want over the UI the more public member function I am going to need. 一个选择是继续前进这个想法,并有一个非常大的公共接口,处理GUI使用的类型( std::stringstd::vector<std::string> ...)我想要的控制越多UI我需要的公共成员功能越多。

  • The other option would be to pass the program state to the GUI and have it decide how it display it, I fear doing this would mean it would give me less fine detail control and would break down the separation of concerns and would mean any changes to the representation of the program state would require changes in the GUI too. 另一个选择是将程序状态传递给GUI并让它决定它如何显示它,我担心这样做会意味着它会给我不那么精细的细节控制并且会打破关注点的分离并且意味着任何改变程序状态的表示也需要在GUI中进行更改。

Any input on the matter would be of great help. 对此事的任何意见都会有很大帮助。

If it makes any difference this is a C++ gui using an ncurses abstraction. 如果它有所不同,那么这是一个使用ncurses抽象的C ++ gui。

It sounds like to me you've thought alot about the M and the V, but not much about the C. The pattern should really be called MCV because the whole idea is that the controller IS the bridge between your model (data) and view (GUI). 听起来我对你有很多关于M和V的看法,但对C来说并不多。该模式应该真正称为MCV,因为整个想法是控制器是你的模型(数据)和视图之间的桥梁(GUI)。 It sounds like you need a controller with most of the functionality you've mentioned. 听起来你需要一个具有你提到的大部分功能的控制器。

Simply put though, your model obviously should know nothing about display and your display (view) should not know how to access the model. 简而言之,您的模型显然应该对显示一无所知,并且您的显示(视图)不应该知道如何访问模型。 You need a controller that reads the data (model) and gives instructions to the display (view). 您需要一个读取数据(模型)的控制器并向显示器(视图)发出指令。 If you have user interaction within the view, the controller can interpret that and modify the model as necessary. 如果您在视图中有用户交互,则控制器可以解释该操作并根据需要修改模型。

The idea is that you never have to change all 3, but if you change the model or the view, you almost always have to update the controller. 这个想法是你永远不必改变所有3,但如果你改变模型或视图,你几乎总是需要更新控制器。

Hope that helps... 希望有帮助......

There is at least one alternative to the giant interface. 巨型界面至少有一种替代方案。 Instead of having a function that handles each thing (size, font, color, what-to-display, etc...) have a singular function that accepts a "role" and data that represents the role. 而不是具有处理每个事物的功能(大小,字体,颜色,显示内容等)具有接受“角色”的单一功能和表示角色的数据。 This requires some sort of wrapper that can contain multiple data types. 这需要某种包含多种数据类型的包装器。

QT's QAbstractItemModel Class Reference has a good example: QT的QAbstractItemModel类参考有一个很好的例子:

QVariant QAbstractItemModel::data ( const QModelIndex & index, int role = Qt::DisplayRole ) const [pure virtual] QVariant QAbstractItemModel :: data(const QModelIndex&index,int role = Qt :: DisplayRole)const [pure virtual]

What that function will do is return the QVariant that represents the role indicated at the index provided. 该函数将执行的操作是返回表示所提供索引处指示的角色的QVariant。

The downside of this approach, is you have to know what roles exist, and what they do. 这种方法的缺点是,您必须知道存在哪些角色以及它们的作用。 QT's default roles are shown here. QT的默认角色如下所示。

I like to have parts of the model able to instrument themselves: 我希望模型的某些部分能够自行测量:

class Model {
private:
    int value;
public:
    void instrument(Instrumenter& instrumenter);
};

The Instrumenter manages the creation of controls. Instrumenter管理控件的创建。 The model will tell it how it can be controlled and give it access to the data. 该模型将告诉它如何控制它并让它访问数据。

void Model::instrument(Instrumenter& instrumenter) {
    instrumenter.addRangeController(0, 100, 5, value);
}

Then for different input devices (eg keyboard, touchscreen) you can create appropriate controls: 然后,对于不同的输入设备(例如键盘,触摸屏),您可以创建适当的控件:

class KeyboardInstrumenter : public Instrumenter {
public:
    void addRangeController(int min, int max, int increments, int& controlled) {
        // create 3 widgets, up arrow, down arrow, and value
    }
};

class TouchscreenInstrumenter : public Instrumenter {
public:
    void addRangeController(int min, int max, int increments, int& controlled) {
        // create slider with min, max and increments
    }
};

Instead of passing in the int directly we could have wrapped it in a controlling object, to aid encapsulation. 我们可以将它包装在一个控制对象中,而不是直接传入int ,以帮助封装。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM