- •Ход лабораторной работы:
- •Метод crc-карточек:
- •Спецификация структуры классов:
- •На данном этапе можно остановиться, если устраивает оценка “удовлетворительно”. Для получения более высокой оценки следует выполнить остальные задания.
- •Формирование тестовой программы, подтверждающей работоспособность модели:
- •Пример простейшей объектной модели
- •Пример тестовой программы
- •Процедура защиты лабораторной работы:
На данном этапе можно остановиться, если устраивает оценка “удовлетворительно”. Для получения более высокой оценки следует выполнить остальные задания.
Отображение основных абстракций на языке программирования C++:
Для всех выявленных классов создать на языке C++ декларации:
классов;
атрибутов;
конструкций, реализующих отношения между классами:
отношения обобщения в виде наследования классов;
отношения агрегации и ассоциации, используя механизмы языка программирования, наиболее близко отражающие семантику диаграммы (например, ссылки, указатели, коллекции, объекты smart pointers, и т.п.).
Снабдить все декларации качественными комментариями (по возможности, на английском языке).
Создать необходимые для организации работы класса объявления и определения ключевых операций, учитывающие семантику всех атрибутов и отношений:
конструктор(ы);
деструктор;
операции-селекторы для описательных атрибутов, для навигации по связям;
операции для формирования связей (если имеются отношения с кратностью 1..*, *..* , либо связь является необязательной).
Заголовки классов следует размещать в отдельных заголовочных файлах, а реализации методов классов следует размещать в отдельных C++ файлах, имена которых должны соответствовать именам классов (например, класс Reservation – объявление в reservation.hpp, реализация в reservation.cpp) ;
Формирование тестовой программы, подтверждающей работоспособность модели:
Составьте консольную тестовую С++ программу, отражающую несколько реалистичных примеров структуры объектной модели, использующих большинство созданных классов:
Программа должна создавать некоторое количество тестовых объектов модели, вручную организовывать связи между ними. Вводить данные об объектах извне во время выполнения не требуется, конкретный состав объектной модели примера может быть жестко задан в коде тестовой программы.
Программа должна уметь обходить созданную модель от вершины иерархии целое-часть ко всем листьям, и при этом распечатывать данные об посещаемых во время обхода объектах (адрес, тип, значения атрибутов).
Вложенность объектов по иерархии целое-часть уместно выразить при помощи отступов или любым другим подходящим способом.
Распечатка может осуществляться или на экран, или в дисковый файл.
Пример простейшей объектной модели
Ниже приведена UML-диаграмма простейшей объектной модели, предназначенной для хранения данных о заказах товаров в магазине.
Созданные классы имеют следующие обязанности:
Класс Shop – представляет собой информацию о магазине, существенную для данного примера. Этот класс будет создаваться только в одном экземпляре за время выполнения программы.
Класс Order – представляет заказ в магазине, имеет уникальный идентификатор, время регистрации. Имеется ярко выраженная операция вычисления стоимости.
Класс Item – представляет строку заказа: товар, количество штук, цену на момент заказа.
Класс Product – представляет собой описание товара, включая уникальный номер, название, описание, код страны происхождения, а также текущую стоимость.
Класс Money – тип-значение, представляющий денежную единицу с целой частью и копейками.
Ниже приведена упрощенная реализация данной модели на языке С++.
money.hpp
#ifndef _MONEY_HPP_
#define _MONEY_HPP_
//-----------------------------------------------------------------------------
#include <string>
//-----------------------------------------------------------------------------
class Money
{
//-------------------------
public:
//-------------------------
Money ();
Money ( unsigned int _integralPart, unsigned char _fractionalPart );
static Money fromString ( const std::string & _moneyAsText );
//-------------------------
std::string toString () const;
bool operator == ( const Money & _m ) const;
Money operator + ( Money const & _m ) const;
Money operator * ( unsigned int _n ) const;
//-------------------------
private:
//-------------------------
unsigned int m_integralPart;
unsigned char m_fractionalPart;
//-------------------------
};
//-----------------------------------------------------------------------------
#endif // _MONEY_HPP_
money.cpp
//-----------------------------------------------------------------------------
#include "money.hpp"
#include <boost/lexical_cast.hpp>
//-----------------------------------------------------------------------------
Money::Money ()
: m_integralPart( 0 ),
m_fractionalPart( 0 )
{
}
//-----------------------------------------------------------------------------
Money::Money ( unsigned int _integralPart, unsigned char _fractionalPart )
: m_integralPart( _integralPart ),
m_fractionalPart( _fractionalPart )
{
}
//-----------------------------------------------------------------------------
Money
Money::fromString ( const std::string & _moneyAsText )
{
double money = boost::lexical_cast< double >( _moneyAsText );
if ( money < 0. )
throw std::exception();
unsigned int integralPart = static_cast< unsigned int >( money );
unsigned char fractionalPart = static_cast< unsigned char >(
( money - integralPart ) * 100.0
);
return Money( integralPart, fractionalPart );
}
//-----------------------------------------------------------------------------
std::string
Money::toString () const
{
char buf[ 100 ];
sprintf( buf, "%d.%02d", m_integralPart, m_fractionalPart );
return buf;
}
//-----------------------------------------------------------------------------
bool
Money::operator == ( const Money & _m ) const
{
return m_integralPart == _m.m_integralPart &&
m_fractionalPart == _m.m_fractionalPart;
}
//-----------------------------------------------------------------------------
Money
Money::operator + ( Money const & _m ) const
{
unsigned int resultIngeralPart = m_integralPart + _m.m_integralPart;
unsigned char resultFractionalPart = m_fractionalPart + _m.m_fractionalPart;
if ( resultFractionalPart >= 100 )
{
++resultIngeralPart;
resultFractionalPart %= 100;
}
return Money( resultIngeralPart, resultFractionalPart );
}
//-----------------------------------------------------------------------------
Money
Money::operator * ( unsigned int _n ) const
{
unsigned int moneyInCents = m_integralPart * 100 + m_fractionalPart;
moneyInCents *= _n;
return Money( moneyInCents / 100, moneyInCents % 100 );
}
//-----------------------------------------------------------------------------
product.hpp
#ifndef _PRODUCT_HPP_
#define _PRODUCT_HPP_
//-----------------------------------------------------------------------------
#include "money.hpp"
#include <string>
//-----------------------------------------------------------------------------
class Product
{
//-------------------------
public:
//-------------------------
Product (
unsigned int _uniqueID,
const std::string & _name,
const std::string & _description,
const Money & _initialPrice
);
//-------------------------
unsigned int getUniqueID () const;
const std::string & getName () const;
const std::string & getDescription () const;
const Money & getCurrentPrice () const;
void setPrice ( const Money & _newPrice );
//-------------------------
private:
//-------------------------
const unsigned int m_uniqueID;
const std::string m_name;
const std::string m_description;
Money m_currentPrice;
//-------------------------
};
//-----------------------------------------------------------------------------
inline
unsigned int
Product::getUniqueID () const
{
return m_uniqueID;
}
//-----------------------------------------------------------------------------
inline
const std::string &
Product::getName () const
{
return m_name;
}
//-----------------------------------------------------------------------------
inline
const std::string &
Product::getDescription () const
{
return m_description;
}
//-----------------------------------------------------------------------------
inline
const Money &
Product::getCurrentPrice () const
{
return m_currentPrice;
}
//-----------------------------------------------------------------------------
inline
void
Product::setPrice ( const Money & _newPrice )
{
m_currentPrice = _newPrice;
}
//-----------------------------------------------------------------------------
#endif // _PRODUCT_HPP_
product.cpp
//-----------------------------------------------------------------------------
#include "product.hpp"
//-----------------------------------------------------------------------------
Product::Product (
unsigned int _uniqueID,
const std::string & _name,
const std::string & _description,
const Money & _initialPrice
)
: m_uniqueID( _uniqueID ),
m_name( _name ),
m_description( _description ),
m_currentPrice( _initialPrice )
{
}
//-----------------------------------------------------------------------------
item.hpp
#ifndef _ITEM_HPP_
#define _ITEM_HPP_
//-----------------------------------------------------------------------------
#include "money.hpp"
//-----------------------------------------------------------------------------
class Product;
//-----------------------------------------------------------------------------
class Item
{
//-------------------------
public:
//-------------------------
Item ( Product const & _product, unsigned int _quantity );
//-------------------------
Product const & getProduct () const;
unsigned int getQuantity () const;
void setQuantity ( unsigned int _newQuantity );
Money getPrice () const;
Money getCost () const;
//-------------------------
private:
//-------------------------
Product const & m_product;
unsigned int m_quantity;
Money const m_price;
//-------------------------
};
//-----------------------------------------------------------------------------
inline
Product const &
Item::getProduct () const
{
return m_product;
}
//-----------------------------------------------------------------------------
inline
unsigned int
Item::getQuantity () const
{
return m_quantity;
}
//-----------------------------------------------------------------------------
inline
void
Item::setQuantity ( unsigned int _newQuantity )
{
m_quantity = _newQuantity;
}
//-----------------------------------------------------------------------------
inline
Money
Item::getPrice () const
{
return m_price;
}
//-----------------------------------------------------------------------------
#endif // _ITEM_HPP_
item.cpp
//-----------------------------------------------------------------------------
#include "item.hpp"
#include "product.hpp"
//-----------------------------------------------------------------------------
Item::Item ( Product const & _product, unsigned int _quantity )
: m_product( _product ),
m_price( _product.getCurrentPrice() ),
m_quantity ( _quantity )
{
}
//-----------------------------------------------------------------------------
Money
Item::getCost () const
{
return m_price * m_quantity;
}
//-----------------------------------------------------------------------------
order.hpp
#ifndef _ORDER_HPP_
#define _ORDER_HPP_
//-----------------------------------------------------------------------------
#include "money.hpp"
#include <vector>
//-----------------------------------------------------------------------------
class Item;
class Product;
//-----------------------------------------------------------------------------
class Order
{
//-------------------------
public:
//-------------------------
Order ( unsigned int _uniqueID, time_t _registeredAt );
~Order ();
//-------------------------
unsigned int getUniqueID () const;
time_t getRegistrationTime () const;
//-------------------------
unsigned int getItemsCount () const;
Item const & getItem ( unsigned int _itemIndex ) const;
Item & newItem ( Product const & _item, unsigned int _quantity );
void removeItem ( Item & _item );
//-------------------------
Money getCost () const;
//-------------------------
private:
//-------------------------
const unsigned int m_uniqueID;
const time_t m_registeredAt;
typedef std::vector< Item * > Items;
Items m_items;
//-------------------------
};
//-----------------------------------------------------------------------------
inline
unsigned int
Order::getUniqueID () const
{
return m_uniqueID;
}
//-----------------------------------------------------------------------------
inline
time_t
Order::getRegistrationTime () const
{
return m_registeredAt;
}
//-----------------------------------------------------------------------------
inline
unsigned int
Order::getItemsCount () const
{
return m_items.size();
}
//-----------------------------------------------------------------------------
inline
Item const &
Order::getItem ( unsigned int _itemIndex ) const
{
return * ( m_items.at( _itemIndex ) );
}
//-----------------------------------------------------------------------------
#endif // _ORDER_HPP_
order.cpp
//-----------------------------------------------------------------------------
#include "order.hpp"
#include "item.hpp"
#include <algorithm>
#include <boost/checked_delete.hpp>
#include <exception>
//-----------------------------------------------------------------------------
Order::Order ( unsigned int _uniqueID, time_t _registeredAt )
: m_uniqueID( _uniqueID ),
m_registeredAt( _registeredAt )
{
}
//-----------------------------------------------------------------------------
Order::~Order ()
{
std::for_each(
m_items.begin(),
m_items.end(),
boost::checked_deleter< Item >()
);
}
//-----------------------------------------------------------------------------
Item &
Order::newItem ( Product const & _product, unsigned int _quantity )
{
Item * pNewItem = new Item( _product, _quantity );
m_items.push_back( pNewItem );
return * pNewItem;
}
//-----------------------------------------------------------------------------
void
Order::removeItem ( Item & _item )
{
Items::iterator it = std::find( m_items.begin(), m_items.end(), & _item );
if ( it == m_items.end() )
throw std::exception();
m_items.erase( it );
}
//-----------------------------------------------------------------------------
Money
Order::getCost () const
{
Money totalCost = Money();
Items::const_iterator it = m_items.begin();
while ( it != m_items.end() )
{
const Item * pItem = * it;
totalCost = totalCost + pItem->getCost();
++ it;
}
return totalCost;
}
//-----------------------------------------------------------------------------
shop.hpp
#ifndef _SHOP_HPP_
#define _SHOP_HPP_
//-----------------------------------------------------------------------------
#include <string>
#include <vector>
#include <map>
#include <memory>
//-----------------------------------------------------------------------------
class Product;
class Order;
class Money;
//-----------------------------------------------------------------------------
class Shop
{
//-------------------------
public:
//-------------------------
Shop ( const std::string &_title );
~Shop ();
//-------------------------
const std::string & getTitle () const;
//-------------------------
Product const & addProduct (
const std::string & _productName,
const std::string & _description,
const Money & _initialPrice
);
void dropProduct ( const std::string & _name );
unsigned int getProductsCount () const;
Product const * findProduct ( const std::string & _name ) const;
class ProductIterator
{
public:
virtual bool hasNext () const = 0;
virtual Product const & getProduct () const = 0;
virtual void next () = 0;
};
std::auto_ptr< ProductIterator > browseProducts () const;
//-------------------------
unsigned int getOrdersCount () const;
const Order & getOrder ( unsigned int _orderIndex ) const;
Order & newOrder ();
//-------------------------
private:
//-------------------------
const std::string m_title;
typedef std::map< std::string, Product * > ProductDescriptions;
ProductDescriptions m_products;
std::vector< Order * > m_orders;
//-------------------------
};
//-----------------------------------------------------------------------------
inline
const std::string &
Shop::getTitle () const
{
return m_title;
}
//-----------------------------------------------------------------------------
inline
unsigned int
Shop::getProductsCount () const
{
return m_products.size();
}
//-----------------------------------------------------------------------------
inline
unsigned int
Shop::getOrdersCount () const
{
return m_orders.size();
}
//-----------------------------------------------------------------------------
inline
const Order &
Shop::getOrder ( unsigned int _orderIndex ) const
{
return *( m_orders.at( _orderIndex ) );
}
//-----------------------------------------------------------------------------
#endif // _SHOP_HPP_
shop.cpp
//-----------------------------------------------------------------------------
#include "shop.hpp"
#include "order.hpp"
#include "product.hpp"
#include <ctime>
#include <algorithm>
#include <exception>
#include <boost/checked_delete.hpp>
//-----------------------------------------------------------------------------
Shop::Shop ( const std::string & _title )
: m_title( _title )
{
}
//-----------------------------------------------------------------------------
Shop::~Shop ()
{
std::for_each(
m_orders.begin(),
m_orders.end(),
boost::checked_deleter< Order >()
);
std::for_each(
m_products.begin(),
m_products.end(),
std::compose1(
boost::checked_deleter< Product >(),
std::select2nd< ProductDescriptions::value_type >()
)
);
}
//-----------------------------------------------------------------------------
Order &
Shop::newOrder ()
{
Order * pNewOrder = new Order( getOrdersCount(), time( NULL ) );
m_orders.push_back( pNewOrder );
return * pNewOrder;
}
//-----------------------------------------------------------------------------
Product const &
Shop::addProduct (
const std::string & _productName,
const std::string & _description,
const Money & _initialPrice
)
{
if ( findProduct( _productName ) )
throw std::exception();
Product * pProduct = new Product(
m_products.size(), /* id */
_productName,
_description,
_initialPrice
);
m_products.insert(
std::make_pair(
pProduct->getName(),
pProduct
)
);
return * pProduct;
}
//-----------------------------------------------------------------------------
void
Shop::dropProduct ( const std::string & _name )
{
ProductDescriptions::iterator it = m_products.find( _name );
if ( it != m_products.end() )
{
Product * pProduct = it->second;
m_products.erase( it );
delete pProduct;
}
else
throw std::exception();
}
//-----------------------------------------------------------------------------
Product const *
Shop::findProduct ( const std::string & _name ) const
{
ProductDescriptions::const_iterator it = m_products.find( _name );
if ( it == m_products.end() )
return NULL;
return it->second;
}
//-----------------------------------------------------------------------------
std::auto_ptr< Shop::ProductIterator >
Shop::browseProducts () const
{
class ProductIteratorImpl
: public ProductIterator
{
//-----------------------
public:
//-----------------------
ProductIteratorImpl ( ProductDescriptions const & _descriptions )
: m_descriptions( _descriptions ),
m_it( _descriptions.begin() )
{
}
//-----------------------
virtual bool hasNext () const
{
return m_it != m_descriptions.end();
}
//-----------------------
virtual Product const & getProduct () const
{
return *( m_it->second );
}
//-----------------------
virtual void next ()
{
++ m_it;
}
//-----------------------
private:
//-----------------------
ProductDescriptions const & m_descriptions;
ProductDescriptions::const_iterator m_it;
//-----------------------
};
return std::auto_ptr< ProductIterator >(
new ProductIteratorImpl( m_products )
);
}
//-----------------------------------------------------------------------------
