文档视图结构

文档/视图体系结构是一个神奇的架构,通过这个架构,我们可以分离应用程序的数据和显示。文档包含了全部的数据,视图从文档获取数据并且显示给用户。针对这个游戏例子,我们得数据是游戏板和有颜色的砖块以及消耗的时间等信息。视图显示游戏板和有颜色的砖块,并且允许用户点击他们。视图同时与用户交互,并且修改文档中的游戏数据,相应地视图被更新以反应数据的变化,如此循环。

文档: 保有数据

终于来到编码时间. 在显示任何数据到屏幕之前,我们要设计好数据的保存方式,所以我们将先从文档部分开始,然后再考虑如何实现将这些数据显示出来。

首先,我们创建一个游戏板类型,让我们叫它CSameGameBoard。通过在解决方案浏览界面(Solution Explorer)单击鼠标右键,然后选择"Add -> Class..." or "Add Class..." 。

在弹出的Generic C++ Class Wizard界面中,我们填上类名CSameGameBoard。

下面是CSameGameBoard类的头文件:

#pragma once

class CSameGameBoard
{
public:
/* Default Constructor */
CSameGameBoard(void);
/* Destructor */
~CSameGameBoard(void);
/* Function to randomly setup the board */
void SetupBoard(void);
/* Get the color at a particular location */
COLORREF GetBoardSpace(int row, int col);
/* Accessor functions to get board size information */
int GetWidth(void) const { return m_nWidth; }
int GetHeight(void) const { return m_nHeight; }
int GetColumns(void) const { return m_nColumns; }
int GetRows(void) const { return m_nRows; }
/* Function to delete the board and free memory */
void DeleteBoard(void);
private:
/* Function to create the board and allocate memory */
void CreateBoard(void);
/* 2D array pointer */
int** m_arrBoard;
/* List of colors, 0 is background and 1-3 are piece colors */
COLORREF m_arrColors[4];
/* Board size information */
int m_nColumns;
int m_nRows;
int m_nHeight;
int m_nWidth;
};

这个类是十分简单的,它包含了一个指针,叫做m_arrBoard,它是一个二维数组,数组的每一个元素的取值为0或三个颜色之一(1-3),这个变量代表了我们看到的整个彩色砖块的全部。我们也添加了跟踪砖块行数 (m_nRows)和列数(m_nColumns)的变量,砖块宽度 (m_nHeight)和砖块高度 (m_nHeight)的变量,以及管理游戏板的一些函数。

create函数需要给二维数组m_arrBoard分配空间来存储游戏板数据,并且初始化所有的砖块为空。setup函数将reset游戏板,并游戏板上的每一个砖块随机地选择一种颜色。最后delete函数重新分配游戏板内存并释放掉之前的内存以防止内存泄漏。

在游戏板类中,有一个COLORREF类型的数组,COLORREF 存储了一个32位的颜色值。这个数组包含了四种颜色:0代表背景色,以及1-3,代表砖块可能的三种颜色(红黄蓝)。二维数组m_arrBoard的每一个元素中存储着这里的四种颜色索引之一。

以下是CSameGameBoard类的实现,在SameGameBoard.cpp文件中。

#include "StdAfx.h"
#include "SameGameBoard.h" CSameGameBoard::CSameGameBoard(void)
: m_arrBoard(NULL),
m_nColumns(15), m_nRows(15),
m_nHeight(35), m_nWidth(35)
{
m_arrColors[0] = RGB( 0, 0, 0);
m_arrColors[1] = RGB(255, 0, 0);
m_arrColors[2] = RGB(255,255, 64);
m_arrColors[3] = RGB( 0, 0,255);
} CSameGameBoard::~CSameGameBoard(void)
{
// Simply delete the board
DeleteBoard();
} void CSameGameBoard::SetupBoard(void)
{
// Create the board if needed
if(m_arrBoard == NULL)
CreateBoard();
// Randomly set each square to a color
for(int row = 0; row < m_nRows; row++)
for(int col = 0; col < m_nColumns; col++)
m_arrBoard[row][col] = (rand() % 3) + 1;
} COLORREF CSameGameBoard::GetBoardSpace(int row, int col)
{
// Check the bounds of the array
if(row < 0 || row >= m_nRows || col < 0 || col >= m_nColumns)
return m_arrColors[0];
return m_arrColors[m_arrBoard[row][col]];
} void CSameGameBoard::DeleteBoard(void)
{
// Don't delete a NULL board
if(m_arrBoard != NULL)
{
for(int row = 0; row < m_nRows; row++)
{
if(m_arrBoard[row] != NULL)
{
// Delete each row first
delete [] m_arrBoard[row];
m_arrBoard[row] = NULL;
}
}
// Finally delete the array of rows
delete [] m_arrBoard;
m_arrBoard = NULL;
}
} void CSameGameBoard::CreateBoard(void)
{
// If there is already a board, delete it
if(m_arrBoard != NULL)
DeleteBoard();
// Create the array of rows
m_arrBoard = new int*[m_nRows];
// Create each row
for(int row = 0; row < m_nRows; row++)
{
m_arrBoard[row] = new int[m_nColumns];
// Set each square to be empty
for(int col = 0; col < m_nColumns; col++)
m_arrBoard[row][col] = 0;
}
}

现在我们已经将游戏板封装成了一个类型,接下来,我们可以在文档类中,创建一个这个类型的实例。需要牢记的是,文档类拥有我们应用的全部数据,它和显示数据的视图类保持分离。下面是文档类的头文件 SameGameDoc.h:

#pragma once

#include "SameGameBoard.h"

class CSameGameDoc : public CDocument
{
protected: // create from serialization only
CSameGameDoc();
virtual ~CSameGameDoc();
DECLARE_DYNCREATE(CSameGameDoc) // Attributes
public: // Operations
public:

/* Functions for accessing the game board */
COLORREF GetBoardSpace(int row, int col)
{ return m_board.GetBoardSpace(row, col); }
void SetupBoard(void) { m_board.SetupBoard(); }
int GetWidth(void) { return m_board.GetWidth(); }
int GetHeight(void) { return m_board.GetHeight(); }
int GetColumns(void) { return m_board.GetColumns(); }
int GetRows(void) { return m_board.GetRows(); }
void DeleteBoard(void) { m_board.DeleteBoard(); }
// Overrides
public:
virtual BOOL OnNewDocument(); protected:

/* Instance of the game board */
CSameGameBoard m_board;
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
};

文档类实际上是一个游戏板类的简单的封装,在后面的文章中我们将增加更多的功能到这里。但是目前它是保持非常简单的,我们增加了一个游戏板类的实例和7个函数,这将允许视图类接入我们的游戏板类的信息经由文档类。文档类所有功能的实现是非常简单的,它们都是间接的调用了游戏板类。

#include "stdafx.h"
#include "SameGame.h" #include "SameGameDoc.h" #ifdef _DEBUG
#define new DEBUG_NEW
#endif // CSameGameDoc
IMPLEMENT_DYNCREATE(CSameGameDoc, CDocument)
BEGIN_MESSAGE_MAP(CSameGameDoc, CDocument)
END_MESSAGE_MAP() // CSameGameDoc construction/destruction
CSameGameDoc::CSameGameDoc()
{
} CSameGameDoc::~CSameGameDoc()
{
} BOOL CSameGameDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;

// Set (or reset) the game board
m_board.SetupBoard();

return TRUE;
}

Really all we added was the call to the SetupBoard function in the OnNewDocument handler in the document. All this does is allows the user to start a new game with the built-in accelerator Ctrl+N or from the menu File->New.

As we continue through the series of articles we'll be adding new functions to both the game board and the document to implement different features for the game but for now we are done with the document and are ready to display this information in the view.

 


"The Same Game": A Simple Game from Start to Finish的更多相关文章

  1. git的一些配置

    git使用socks代理加速 原来git可以配置socks代理的,真好,从github上clone了opencv的代码,基本上是满速了. 首先需要配置shadowsocks,然后通过GUI客户端(或命 ...

  2. PHP设计模式(一)简单工厂模式 (Simple Factory For PHP)

    最近天气变化无常,身为程序猿的寡人!~终究难耐天气的挑战,病倒了,果然,程序猿还需多保养自己的身体,有句话这么说:一生只有两件事能报复你:不够努力的辜负和过度消耗身体的后患.话不多说,开始吧. 一.什 ...

  3. Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】

    原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part3-factory/ Design ...

  4. WATERHAMMER: A COMPLEX PHENOMENON WITH A SIMPLE SOLUTION

    开启阅读模式 WATERHAMMER A COMPLEX PHENOMENON WITH A SIMPLE SOLUTION Waterhammer is an impact load that is ...

  5. BZOJ 3489: A simple rmq problem

    3489: A simple rmq problem Time Limit: 40 Sec  Memory Limit: 600 MBSubmit: 1594  Solved: 520[Submit] ...

  6. Le lié à la légèreté semblait être et donc plus simple

    Il est toutefois vraiment à partir www.runmasterfr.com/free-40-flyknit-2015-hommes-c-1_58_59.html de ...

  7. ZOJ 3686 A Simple Tree Problem

    A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a rooted tree, each no ...

  8. 设计模式之简单工厂模式Simple Factory(四创建型)

    工厂模式简介. 工厂模式专门负责将大量有共同接口的类实例化 工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类. 工厂模式有三种形态: 1.简单工厂模式Simple Factory ...

  9. HDU 5795 A Simple Nim 打表求SG函数的规律

    A Simple Nim Problem Description   Two players take turns picking candies from n heaps,the player wh ...

随机推荐

  1. HDU 4712 Hamming Distance(随机算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4712 题目大意:任意两个数按位异或后二进制中含1的个数被称为海明距离,给定n个数,求出任意其中两个最小 ...

  2. C++里容易忽视却不能忽视的

    1 define 只是简单地文本替换. 2 每个机器的字长不同. 3 每个类型在不同的机器上,所占用的内存空间不同. 4 每个机器内部的字节大小端不同. 5 并不是所有的编译器或机器都支持最新的C++ ...

  3. getopt getopt_long

    getopt_long支持长选项的命令行解析,使用man getopt_long,得到其声明如下: #include <getopt.h> int getopt_long(int argc ...

  4. javaScript中with的用法

    1 JavaScript中的with语句的作用是为逐级的对象访问提供命名空间式的速写方式, 也就是在指定的代码区域, 直接通过节点名称调用对象 初次接触到with用法,是这样一段代码: 1 2 3 4 ...

  5. h5添加音乐

    http://changziming.com/post-209.html 加入HTML代码,因为是绑定在每一页的右上方(或者其他位置),定位用了fixed,所以在页面底部/body之前加上html代码 ...

  6. OpenCart框架运行流程介绍

    框架运行流程介绍 这样的一个get请求http://hostname/index.php?route=common/home 发生了什么? 1. 开始执行入口文件index.php. 2. requi ...

  7. epoll和select区别

    先说下本文框架,先是问题引出,然后概括两个机制的区别和联系,最后介绍每个接口的用法 一.问题引出 联系区别 问题的引出,当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一 ...

  8. ASP.NET MVC轻教程 Step By Step 1 ——入门

    使用ASP.NET MVC有一段时间了,本人还是非常喜欢ASP.NET MVC这个框架模式的.在经历了WebForm复杂粗暴的做法后,自然感觉简洁优雅的MVC清新可人,只不过WebForm和MVC的设 ...

  9. 7 -- Spring的基本用法 -- 8...

    7.8 深入理解容器中的Bean 7.8.1 抽象Bean与子Bean 把多个<bean.../>配置中相同的信息提取出来,集中成配置模版------这个配置模版并不是真正的Bean,因此 ...

  10. iOS - 应用程序国际化

    开发的移动应用更希望获取更多用户,走向世界,这就需要应用国际化,国际化其实就是多语言.这篇文章介绍Xcode4.5以后的国际化,包括应用名国际化和应用内容国际化.如果是Xcode4.5之前版本请参考. ...