Приемы применения статических членов — Factory Method



 

Довольно распространенной ситуацией является случай, когда некоторые комбинации аргументов класса не являются допустимыми. Например, описанный выше класс Student не должен считать корректными значения оценки за пределами интервала [1;100]. Объект, нарушающие данное инвариантное условие существовать не должен, поскольку не соблюдается важное ограничение из рассматриваемой предметной области.

 

Обычные функции, сталкиваясь с подобной проблемой, осуществляют проверку, и предпринимают те или иные действия по обработке возникшей ошибки. Простейшим вариантом обработки является возврат значения, означающего неудачу (например, функция fopen возвращает nullptr, если файл открыть не удается) или генерация исключительной ситуации. Когда ошибка возникает в конструкторе, то возникают определенные сложности:

● конструкторы не имеют возвращаемого типа, соответственно, не доступен вариант обработки с возвратом значения, означающего неудачу - доступно лишь решение, генерирующее исключительную ситуацию (инструкция throw);

● конструктор должен после завершения работы оставить объект в корректном начальном состоянии, что, в случае передачи ошибочных аргументов может быть затруднительным и даже невозможным (либо генерировать исключительную ситуацию, оставив объект недоконструированным);

● возможно, конструктор уже выделил часть ресурсов до момента обнаружения ошибки, и их требуется корректно освободить, поскольку деструкторы недоконструированных объектов не вызываются.

 

По тем или иным соображениям генерация исключительной ситуации для обработки нарушения инвариантных условий может быть нежелательной. Одной из возможных причин может быть относительно высокая стоимость генерации и перехвата исключений с точки зрения производительности. Кроме того, исключение в конструкторе объектов, выделяемых динамически, по-прежнему означает, что, помимо конструктора, вызывается пара глобальных операторов new/delete для низкоуровневого распределения памяти (new вызывается до вызова конструктора, а delete будет вызван автоматически при генерации исключения в конструкторе).

 

Решить описанную проблему можно применением статического МЕТОДА-ФАБРИКИ (Factory Method). Такой метод будет проверять корректность переданных аргументов до момента создания объекта, а лишь убедившись в их правильности, вызовет оператор mew и конструктор. Метод-фабрику обычно называют Create или Make. Сам конструктор может опустить все проверки и предполагать, что данные придут корректными. Чтобы исключить случайный прямой вызов конструктора, не делающего проверок аргументов, его следует поместить в зону доступа private. В таком случае создание объекта будет возможно только через вызов метода-фабрики.

 

Ниже приведены необходимые изменения для добавления метода-фабрики в классе Student:

 

student.hpp

   

#ifndef _STUDENT_HPP_

#define _STUDENT_HPP_

 

//*******************************************************************************

 

class Student

{

 

/*-----------------------------------------------------------------*/

 

// Обычные (нестатические) переменные-члены (храним в объекте)

const char * m_LastName;

const int m_Mark;

 

/*-----------------------------------------------------------------*/

 

// Закрытый конструктор

Student ( const char * _lastName, int _mark );

 

/*-----------------------------------------------------------------*/

 

public:

 

// Статический метод-фабрика

static Student* Make ( const char * _lastName, int _mark );

 

/*-----------------------------------------------------------------*/

 

};

 

//*******************************************************************************

 

#endif // _STUDENT_HPP_

 

 

student.cpp

 

#include "student.hpp"

#include <stdexcept>

 

//*******************************************************************************

 

// Реализация конструктора

Student::Student ( const char * _lastName, int _mark )

: m_LastName( _lastName ), m_Mark( _mark )

{

}

 

 

//*******************************************************************************

 

// Реализация статического метода-фабрики

Student *Student::Make ( const char * _lastName, int _mark )

{

// Делаем проверку ограничения на оценки

if ( _mark >= 1 && _mark <= 100 )

   // Все корректно, можно создавать объект

   return new Student( _lastName, _mark );

 

Else

{

   // Сигнализируем об ошибке, не создаем объект

   throw std::logic_error( "Invalid student data" );

}

}

 

 

test.cpp

 

#include "student.hpp"

 

#include <cassert>

#include <stdexcept>

 

/*****************************************************************************/

 

int main ()

{

// Создаем студента с корректным баллом через метод-фабрику.

// Ожидаем успех

Student * pStudent = Student::Make( "Ivanov", 75 );

delete pStudent;

 

// Создаем студента с превышающим допустимый баллом через метод-фабрику.

// Ожидаем неудачу

Try

{

   pStudent = Student::Make( "Petrov", 101 );

   assert( ! "Exception must have been thrown!" );

}

catch ( std::exception & )

{

   // Исключение ожидаемо

}

 

// Создаем студента со слишком маленьким баллом через метод-фабрику.

// Ожидаем неудачу

Try

{

   pStudent = Student::Make( "Sidorov", 0 );

   assert( !"Exception must have been thrown!" );

}

catch ( std::exception & )

{

   // Исключение ожидаемо

}

}

 

/*****************************************************************************/

 


Дата добавления: 2021-01-21; просмотров: 62; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!