
- •Coursework thesis
- •Task for coursework
- •Abstract
- •List of abbreviations
- •Introduction
- •Domain analysis
- •Designing the system
- •Interface classes iSerializible, iEmissionable and iCloneable
- •Class for transport information
- •Bus, Plane, Train classes
- •Data storing. Transport schedule class
- •Array of pointers. Container class.
- •User Interface Design
- •Software implementation
- •Clock and Time classes.
- •Coordinates structure implementation
- •StationInfo structure implementation
- •IEmissionable, iSerializable and iCloneable implementation
- •TransportInfo class implementation
- •Bus, Plane, Train class implementation
- •TransportSchedule class implementation
- •Conclusions
- •References
- •Appendix a File Time.H
- •File Time.Cpp
- •File Clocks.H
- •File Clocks.Cpp
- •File iSerializable.H
- •File iEmissionable.H
- •File iCloneable.H
- •File stdafx.H
- •File stdafx.Cpp
- •CoordinatesData.Json
- •File transports.Csv
- •File Coordinates.Cpp
- •File main.Cpp
- •File Route.Cpp
- •File Route.H
- •File StationInfo. Cpp
- •File StationInfo.H
- •File TransportSchedule.H
- •File TransportSchedule.Cpp
- •File PtrArray.Cpp
- •File TransportInfo.Cpp
- •File TransportInfo.H
- •File Bus.H
- •File Bus.Cpp
- •File Plane.H
- •File Plane.Cpp
- •File Train.H
- •File Train.Cpp
- •Appendix b
Interface classes iSerializible, iEmissionable and iCloneable
The system depends on the external data, i.e., data in the file, hence my system has to be able to write to files and read from them. For simplicity and maintainability, define interface ISerializable(see figure 2.1) with three template parameters: type of the object used to work with files, via what buffer the serialization(writing to a file) is performed, and so with the buffer to deserialize(read from file) data from. The all methods are pure virtual and virtual destructor is set to default.
Figure 2.1 - ISerializable interface design
Inherently almost all transports have some kind of emissions, and so with transports in my program. To show users how much they could save emission in the air by travelling one or the other route can help people, who strongly care about nature, to indulge their striving. For this kind of functionality, I defined an interface IEmissionable(see figure 2.2) that, by its name, enforces all classes that are derived from it to define two main methods: how much fuel transport consumes by travelling particular distance and by this data to calculate emissions.
Figure 2.2 - IEmissionable interface design
It also worth mentioning that parameterless constructor for this interface is deleted to explicitly enforce that emissionFactor field must always be initializied with a value.
As can be seen on figure 1.1 our Vehicles hold a lot of data: information about time, stations, coordinates and so we should store them in a container as pointers but there is no an appropriate array in C++ to store those correctly and hence we must create one. For these purposes we define interface which enforces all the derived classes to implement clone() method so that our array could operate correctly.
Figure 2.3 - ICloneable interface design
Class for transport information
The key class of our program. It has to be a base class for all our transports that are used in a schedule. Consists of mandatory fields that must be in each and every public transport. The ones are places below with explanations. This class implements all the interfaces stated in 1.1 chapter.
ID. It’s obvious that every public transport must have its own unique ID, and it might be clearly visible that this field must be constant(const), but there is a reason this should not. When declaring const identifier you tell the compile that this data should never be changed. The idea is that there are reasons when some transports should take another route rather than their own. For instance, some bus has broken down and another from other route has to replace it. When you can’t change the ID of the transport it will mislead people: they know that this specific bus from Kharkiv to Kyiv goes under ID of 10001, but the ID 10012 comes instead of it. Passengers would be confused, and simple changing of the number would prevent this situation.
Departure and destination information. The information about where transport goes from and to is the most necessary, so we need field with station name. The easiest way to represent this is by using string representation. For example, “Kyiv”, the other way might be const char* data, but it would demand controlling the correct memory flow, no leaks, and errors which is complicated. Internal std::string data type allows programmer to operate safely without any concerns and does not take a lot of computer resources.
The same thing with time. C++ language does not explicitly have Time class to store hours, minutes, and seconds, so creating a custom class is recommendable. Class Time must have methods to input/output data, setTime based on the given hours, minutes and hours, and string object parsing to parse string of type “hh:mm::ss”. We need the last one for the better data storage. Class must be comparable, for this purpose we define spaceship operator[4]. This class is a parent of class Clocks. The one, inherently, must store the time with restrictions, e.g., 23 is maximum value for hours and 59 for minutes and seconds.
Figure 2.4 - Clocks class design
In this diagram we do not need to show that setTime is overridden because according to a documentation user can either show the overridden method by ‘^’ preceding the name or might not show[3].
But how do we calculate the fuel consumption of a transport without distance. This data is necessary to provide accurate information about carbon emissions of a transport. For this purpose, we define structure Coordinates with static method to calculate distance between two points which will contain data about longitude and latitude of a city. This won’t provide the most accurate information about emissions, but it gives us the opportunity to approximate the emissions. Define class Coordinates with private fields longitude and latitude, getters for these and static method to calculate distance between points. For this calculations, the equirectangular approximation[1](also known as the "Haversine formula" approximation or "planar approximation") is used. The formula can be expressed as
where R is the radius of the Earth(mean radius = 6.371 km).
Figure 2.5 - Coordinates class design
After some considerations, it was decided that the information about station can be merged into one structure called StationInfo. Such union permits to separate the data, which will ensure better code reusability and maintenance. Structure will be implemented in accordance with the following Class Box.
Figure 2.6 - StationInfo structure design
Fee. The fee field is required because no transport is free unless otherwise is stated. Should store number in form of an integer or floating-point(double). The double value is chosen for potential future development: discounts, sales etc. that might cause non-integer value.
TransportInfo class will as well override ISerializable::getTypeString() method as in the program we will have a container that maps type representation of a transport with its corresponding string value. In our case the type is TranportType enumeration(figure 2.6). Where all three means of transports are listed.
Figure 2.7 - TransportType enumeration
The type templates of ISerializable are instantiated in TransportInfo as ObjectType -> TransportTypes, WriteToBuffer -> ofstream, ReadFromBuffer -> stringstream. And mentioning ICloneable, it is simply TypeToClone -> TransportInfo*.
Contemplating all the above stated we now can combine and design the generic TransportInfo class.
Figure 2.8 - TransportInfo structure design