Models and Views
COS2614 - Programming: Contemporary Concepts · Higher-Level Programming
Models and Views
This topic covers the concept of Models and Views in the context of programming, specifically focusing on how data is represented and displayed in user interfaces. Understanding this concept is crucial because it helps organise data and provides a clear separation between the data (model) and its representation (view), leading to better software design.
Key idea: After studying this topic, you should be able to:
- Explain the Model-View architecture.
- Implement a basic model and view in C++.
- Understand the role of factories in creating objects.
- Apply the principles of object ownership and memory management.
Understanding the Model-View Architecture
The Model-View architecture is a design pattern that separates an application into three interconnected components:
- Model: This represents the data and the business logic of the application. It directly manages the data, logic, and rules of the application.
- View: This is the user interface that displays the data from the model. It presents the model's data to the user and sends user commands to the model.
- Controller: This mediates input, converting it to commands for the model or view. (Note: While the controller is not the focus of this topic, it is important to understand its role.)
Example of Model-View Interaction
Consider a simple application that displays a list of customers. The customer data is stored in a model, and the view is responsible for displaying this data in a user-friendly format. When a user adds a new customer, the view sends this information to the model, which updates its data.
Tip: Always ensure that your model is independent of the view to promote reusability and maintainability.
Implementing a Basic Model and View in C++
In C++, you can create a simple model and view using classes. Below is an example of a basic Customer model and a corresponding view.
class Customer {
public:
Customer(QString name, QString email) : m_name(name), m_email(email) {}
QString getName() const { return m_name; }
QString getEmail() const { return m_email; }
private:
QString m_name;
QString m_email;
};
class CustomerView {
public:
void displayCustomer(const Customer& customer) {
std::cout << "Name: " << customer.getName() << ", Email: " << customer.getEmail() << std::endl;
}
};In this example, the Customer class represents the model, while the CustomerView class represents the view that displays customer information.
Creating Objects with Factories
To manage object creation, you can use the factory pattern. A factory class can create instances of your model while ensuring proper memory management.
class CustomerFactory {
public:
static Customer* createCustomer(QString name, QString email) {
Customer* customer = new Customer(name, email);
return customer;
}
};The factory method createCustomer creates a new instance of Customer and returns it. This method ensures that the created object has a defined lifecycle.
Watch out: Always remember to manage memory properly. If you create objects with new, ensure you delete them when they are no longer needed to prevent memory leaks.
Memory Management and Object Ownership
In C++, managing memory and understanding object ownership is crucial. When you create an object using new, you are responsible for deleting it. If an object is assigned a parent, it will automatically be deleted when the parent is deleted, as shown in the following example:
class ObjectFactory {
public:
static ObjectFactory* instance() {
static ObjectFactory* singleton = 0;
if (singleton == 0) {
singleton = new ObjectFactory();
}
return singleton;
}
Customer* newCustomer(QString name, QString email) {
Customer* customer = new Customer(name, email);
customer->setParent(this);
return customer;
}
};In this example, the ObjectFactory creates customers and sets their parent to itself. This ensures that the customers are deleted when the factory is destroyed.
Best Practices for Memory Management
- Always set a parent for QObject-derived classes to manage memory automatically.
- Use smart pointers (e.g.,
std::unique_ptr) where possible to avoid manual memory management. - Document ownership rules clearly in your code.
Summary
- The Model-View architecture separates data from its presentation.
- Implement models and views using classes in C++.
- Use factory methods for object creation to manage memory effectively.
- Understand and apply principles of object ownership and memory management.
Check your understanding
- What are the three components of the Model-View architecture?
- How does the factory pattern assist in object creation?
- What are the benefits of setting a parent for QObject-derived classes?
- Explain the importance of memory management in C++ programming.