C/C++ 编程代写
当前位置:以往案例 > >CS案例:C++案例加急课
2017-09-27



Introduction
This document specifies the requirements for the first project of the Software Development with C++ course, SP5 2018. This project will develop your skills by allowing you to put into practice what has been taught in class during the first 5 weeks of the course.


The project will require you to design, implement, test, and debug a text-based Roguelike dungeon crawler game using object-oriented methods and the application of appropriate design patterns. In addition, it will require you to use version control to keep track of your implementation as you progress through the project and to document your classes appropriately using Doxygen comments. The work in this project is to be performed individually and will be submitted via LearnOnline at the end of week 8: due by 14 September 2018 11:59 PM. Refer to section Submission Details for specific instructions.


If any parts of this specification appear unclear, please ensure you seek clarification.



Learning Outcomes
After completing this project, you will have learnt to:


· Design a class hierarchy using UML

· Apply Object-Oriented principles (encapsulation, reuse, etc.) and Design Patterns to the software design

· Implement the software design in C++ using class inheritance and polymorphism features

· Write well-behaved constructors and destructors for C++ classes

· Use C++ pointers (including smart pointers) and dynamic memory allocation and management

· Use stream I/O and manipulators for formatted input and output

· Write code adhering to coding standards, guidelines and good programming practices


Design Patterns
In developing the class design for the Dungeon Crawler game, the following the Design Patterns must be incorporated:


· Singleton

· Builder

· Decorator

· Strategy

This section provides brief descriptions of each relevant design pattern in turn. For more information refer to the book from which these summaries are derived:

Gamma, E, Helm, R, Johnson, R and Vlissides, J 1995, Design patterns: elements of reusable object-oriented



software, Addison-Wesley, ISBN: 978-0-201-63361-0.1 Be aware that the C++ ples from the book are for an older version of C++. If using them for guidance, they must be updated to C++ 14.


Adequate descriptions of the above patterns along with some code ples can also be found on Wikipedia:


· Singleton: https://en.wikipedia.org/wiki/Singleton_pattern

· Builder: https://en.wikipedia.org/wiki/Builder_pattern

· Decorator: https://en.wikipedia.org/wiki/Decorator_pattern

· Strategy: https://en.wikipedia.org/wiki/Strategy_pattern


Singleton
The Singleton pattern addresses the problem of ensuring that a class has only one instance. Moreover, the one instance is easily accessible but in a controlled fashion. Such a pattern arises in situations where a single, globally accessible interface to a system or subsystem is required and, hence, is often used with other patterns such as Façade and Abstract Factory. An ple of singleton a singleton is an application wide configuration. Rather than parsing the configuration file multiple times and storing multiple copies in memory, the configuration file should be read once and stored once. Moreover, since various parts of the application may need to access different settings, the configuration should be globally accessible to ensure the configuration is accessible when needed. Other ples include: a single print spooler governing access to the printer resources, a single thread/connection pool handing out connections or threads to clients that request them, etc.


When to Use
The Singleton pattern should be applied to a class when:


1. Exactly one instance of the class must exist

2. A well-known access point to the instance is required


In general, the extensibility of a Singleton through subclassing should also be considered. It will not be required for this project; however, it is important to note as a common criticism of the Singleton pattern is that it becomes tied to implementation and makes testing difficult due to the inability to replace the singleton instance with a mock (i.e., a test specific class that is not a complete implementation).

image.pngGeneral Structure

A simple representation of the Singleton pattern includes only a Singleton class, i.e., the class that should be a Singleton, containing: a static member function instance() that returns the unique instance of the class, a hidden constructor, and a static data member to hold the unique instance of the class.


Note the ‘+’ indicates public accessibility and ‘-‘ indicates private accessibility. If considering extensibility of the

Singleton through subclassing, the constructor should be protected rather than private.


1 Scanned PDFs of the relevant sections are available from the course website as the library has limited copies of the book.



Implementation Hints
In C++, the compiler may generate some constructors and operators for you. Ensure you prevent the Singleton from accidentally being copied or assigned in ways you do not intend by deleting any automatically generated members that you do not need.


In C++, the static data member can be implemented in two different ways: within the scope of the class or within the scope of the function. Consider the consequences of each approach and justify your implementation choice in your comments.


Builder
The purpose of the Builder pattern is to separate the representation of a complex object from the process used to construct it. Further, such separation allows different representations to be constructed from the same process. For ple, a Parser using a Builder to construct a parse tree in different systems: the recognition of the syntax is handled by the parser, which calls the builder to create the appropriate parse nodes and retrieves the final parse tree from the Builder once the parsing is complete. The different representations may or may not be related, for ple, an executable parse tree of the parsed syntax, a parse tree for another language (such as in code transformation), or a composition of widgets for visualising the text processed by the Parser.


An important aspect of the Builder pattern that differentiates it from other creational patterns is that it supports the creation of complex objects in a step-by-step process, rather than all-at-once.


When to Use
The Builder pattern should be applied when:


· the construction process is, or should be, independent of the object, its parts, and the way that it is assembled

· the construction process should allow for different representations to be created.

Note that there does not always have to be multiple representations, only that multiple representations are possible. One of the motivations for good design is to support future change more easily.


General Structure
image.png

The Builder pattern contains several interacting classes, including:


· the Director, which represents the entity that requires the object to be constructed and ‘directs’ the

Builder to construct it;

· the Builder, which specifies an abstract interface for constructing any Product object, this may include many different member functions for constructing different types of parts;

· one or more ConcreteBuilders, which create specific Products from its parts by implementing the abstract Builder interface and allows the Product to be retrieved once complete as it maintains the representation internally during construction;



· the Product class, which represents the complex object being created by a ConcreteBuilder as well as its parts. Note: this does not mean the classes for the parts are encapsulated by the Product class, only that the diagram is simplified to not explicitly illustrate any of the Product’s parts.


Implementation Hints
If the representations being constructed by the different ConcreteBuilders are related, the abstract Builder

may declare an appropriate getResult() member function as part of its interface.


The ConcreteBuilder object is not required to be supplied to the Director via a constructor, it could also be a parameter to a member function.


Decorator
The Decorator pattern is used to dynamically associate additional functionality or responsibilities to an object, rather than a class. The common exemplar is the addition of a border to GUI widgets: the widgets themselves may or may not have a border, scroll bar, etc., but can be wrapped in an object that understands how to draw a border around the widget, i.e., a decorator. This pattern is an ple of favouring composition over inheritance, which results in greater flexibility. Consider using inheritance to add a border to a widget, displaying the widget would require a check for whether a border should be drawn then display the border followed by displaying the widget itself. Now consider that widgets can have a scroll-bar and a border, displaying the widget would have to check and display the border then check and display the scroll-bar. Most, if not all, widget classes would inherit this capability even though many instances of those widgets would not require it. By separating out these responsibilities into distinct classes that can be composed, the widget can worry about displaying itself, while the border decorator can focus on drawing a border and the scroll-bar decorator can focus on the scroll-bar. This has no impact on the calling code as the decorators conform to the same interface as widgets but delegate most function calls straight to their component, which may be another decorator. Apart from reuse, this pattern supports extensibility as new decorators can be added without affecting those already implemented.


When to Use
The decorator pattern should be used when:


· responsibilities or functionality should be added to specific objects dynamically,

· such responsibilities can be removed dynamically, and

· the use of inheritance is impractical, e.g., supporting all combinations of responsibilities would become cumbersome.


Note: The decorator pattern is best applied when the shared base class is (or can be made) lightweight, with few data members, otherwise the overhead for having many objects may become a problem. This is in contrast to the strategy pattern (see next section), which can otherwise be used in similar situations.



General Structure
image.png

The Decorator pattern includes several classes with responsibilities as follows:


· an abstract Component that defines the common interface for objects that support dynamically added responsibilities;

· the ConcreteComponent, which represents the specific types of object that can have responsibilities attached;

· the abstract Decorator that maintains compatibility to the Component interface by referring to a

Component object and delegating the function calls to the underlying object;

· the ConcereteDecorator classes, which add responsibilities to the Component object and may provide additional behaviour and/or state.


Implementation Hints
When implementing the decorator pattern, more than one operation of the component type can have their output modified by a decorator. For ple, a border decorator might decorate the draw operation (to display the border) as well as the size operation (to add the border thickness to the reported size of the widget).


Strategy
To encapsulate a group of similar algorithms and allow them to be used interchangeably, the Strategy pattern should be used. Such an approach simplifies client code by separating the different algorithm variants into their own classes, rather than implementing them all in the one place, and allows an appropriate algorithm to be chosen dynamically based on the context. It can also allow behaviour to reused between objects of different types. A simple ple of Strategy would be the formatting of dates as a string based on locale: the different formatting algorithms are implemented independently, and the locale object is configured with the desired algorithm. The strategy pattern can also be seen in libraries for Data Science where, for ple, different clustering algorithms are implemented as classes with the same interface, so they can be used (for the most part) interchangeably. Another feature of the strategy pattern is that it allows the algorithm implementations to encapsulate internal state required to perform the operation without exposing it.


When to Use
There are several situations in which a Strategy pattern is applicable. The situations most relevant to this project are when:


· many related classes differ primarily in their behaviour, and

· multiple variants of an algorithm are necessary.



Note: the strategy pattern can be applied more efficiently to fat objects, i.e., objects with many data members, by being an extra data member themselves. As such, the strategy pattern changes behaviour from the inside-out whereas the decorator pattern changes behaviour from the outside-in.

image.png

General Structure

The classes and responsibilities in the Strategy pattern include:


· the abstract Strategy class, which defines the interface that all the algorithm variants support;

· the ConcreteStrategy classes that each define a variant of the algorithm conforming the interface defined by the abstract Strategy class;

· a Context class that references a Strategy object, which may be configured at creation or dynamically through an interface (e.g., setAlgorithm(…)), and executes the Strategy object when desired.


Implementation Hints
In C++, the function call operator ‘()’ can be overloaded like other operators, which makes it easy to execute the strategy object as if it were a function. Overloading the function call operator will not be explicitly covered until closer to the submission deadline of this project and, therefore, is not required in your implementation.


The interface of the Strategy class may specify parameters such that all the information it expects to require is passed in. Alternatively, the Strategy interface may accept a reference to the Context class, so that the Context can pass itself to the Strategy object, allowing it to retrieve data from the Context object as required. Consider the consequences of each approach and justify your implementation choice in your comments.


Usually the ConcreteStrategy will be chosen by the client and passed to the Context; however, in this project the ConcreteStrategy may be predetermined in most instances.

在线提交订单