Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > Технологии > Общие вопросы по программированию, компьютерным наукам
Регистрация

Восстановить пароль
Повторная активизация e-mail


Ответ
 
Опции темы
Старый 13.06.2009, 10:29   #11
alexBlack
Новичок
Профессионал
 
Регистрация: 12.10.2007
Адрес: -
Сообщений: 1,204
Репутация: 920
По умолчанию

Цитата:
Сообщение от pu4koff Посмотреть сообщение
alexBlack, как интересно только будет выглядеть реализация этого фабричного метода? Класс интерфейса же абстрактный, соответственно создать его никак нельзя. Соответственно, будет строгая зависимость от какого-то другого класса, реализующего этот интерфейс.
Да, абстрактный и создавать его нельзя и нет смысла. Создаем конечно -же объект класса, который реализует интерфейс:

Код:

 class A_Interface
{
 public:
  static A_Interface* create_A();
  virtual ~A_Interface() {}
  virtual void do_something() {};
};

//--- Это часть реализации, скрытая от пользователей бибилиотеки
class A : public A_Interface
{
 public:
	 void do_something() {};
};

A_Interface* A_Interface::create_A()  
{
	return new A(); 
}
//------------------

// Использование
	A_Interface* a = A_Interface::create_A();

Суть шаблона интерфейс (как я понимаю) именно скрыть реализацию.
Можно посмотреть на это по другому. Если убрать слово интерфейс - то получается обычное дерево наследования и суть шаблона - принудительно заставить использовать базовый класс вместо потомков.

Цитата:
Таким образом, нет никакой необходимости в абстрактном классе интерфейса и почему бы его сразу не сделать обычным классом и создавать через вызов конструктора, а не через фабричный метод? Ну разве что для тестирования может пригодится (в фабричном методе возвращать какой-то тестовый класс для проверки работоспособности).
Это если фабрика всегда возвращает один и тот-же класс, как у меня в примере. Вот (несколько надуманный, но более практичного в голову не приходит) пример:

Есть ряд лексем, каждой соответствует рисунок. Класс, который рисует лексему просто передает ее как параметр фабричному методу. Фабричный метод создает экземпляр класса, соответствующего лексеме и возвращает его (количество классов соответствует количеству лексем, но использующий объект видит только интерфейс).

Цитата:
Мне кажется, было бы логичнее сделать этот фабричный метод вне класса, чтобы интерфейс уже не зависел от конкретной его реализации.
И включить его в другой класс. Какой ? В любом случае это будет другой шаблон проектирования.

Цитата:
Сообщение от atomicxp Посмотреть сообщение
Для меня реализация шаблона проектирования интерфейса это прежде всего способ управления другими классами. Если он содержит что-то помимо чисто абстрактных методов, то это не интерфейс.
А как я понял, шаблон-интерфейс - это не способ управления классами, а в бОльшей степени способ уменьшения сложности. Кроме управления нужно еще и скрыть знание об управляемых классах.

М.б. следует рассматривать шаблоны на примерах, более приближенных к реальности.
В книгах, где они рассматриваются чуть ли не первым пунктом идет область применения шаблона.
(И шаблон-интерфейс упоминается похоже только в этой статье. м.б. не стоит заострять на нем внимания)

Последний раз редактировалось alexBlack; 13.06.2009 в 10:33.
alexBlack вне форума   Ответить с цитированием
Старый 13.06.2009, 14:19   #12
atomicxp
Форумчанин
 
Аватар для atomicxp
 
Регистрация: 01.05.2009
Сообщений: 111
Репутация: 63

skype: atomicxp
Радость

Вариант интерфейса.

Код:

#include <iostream>

using namespace std;

class InterfaceA
{
 protected:  // запрещает удалять derived объект через интерфейс
    ~InterfaceA(){}
 public:
    virtual void ma() = 0;
    virtual void mb() = 0;
};

class ClassA : public InterfaceA
{
 protected:
    ~ClassA(){ cout << "Desctruction ClassA" << endl; }
 public:
    void ma()
    {
        cout << "ClassA: Method A" << endl;
    }
    void mb()
    {
        cout << "ClassA: Method B" << endl;
    }
};

void Testing(ClassA* classA)
{
    InterfaceA* interfaceA;

    interfaceA = classA;

    interfaceA->ma();
    interfaceA->mb();

    delete interfaceA; // |38|ошибка: в данном контексте|
}

int main()
{
    ClassA* classA = new ClassA();

    Testing(classA);

/*    classA->ma();
    classA->mb();

    delete classA;*/

    return 0;
}

Цитата:
/media/Data_01/Work/Start/AxCoreProjects/InterfaceNix/main.cpp||In function ‘void Testing(ClassA*)’:|
/media/Data_01/Work/Start/AxCoreProjects/InterfaceNix/main.cpp|8|ошибка: ‘InterfaceA::~InterfaceA()’ is protected|
/media/Data_01/Work/Start/AxCoreProjects/InterfaceNix/main.cpp|38|ошибка: в данном контексте|
||=== Build finished: 2 errors, 0 warnings ===|
Деструктор интерфейса защищён, значит нельзя вызвать его для объекта использующего интерфейс, через сам интерфейс и утечка памяти невозможна. Таким образом виртуальный деструктор не нужен.

Последний раз редактировалось atomicxp; 13.06.2009 в 15:21.
atomicxp вне форума   Ответить с цитированием
Старый 13.06.2009, 15:42   #13
pu4koff
Профессионал
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,639
Репутация: 3613
По умолчанию

Цитата:
Сообщение от atomicxp Посмотреть сообщение
Деструктор интерфейса защищён, значит нельзя вызвать его для объекта использующего интерфейс, через сам интерфейс и утечка памяти невозможна. Таким образом виртуальный деструктор не нужен.
Получили мы объект посредством вызова фабричного метода как указатель на интерфейс. Как тогда удалить этот объект, когда он станет ненужным?
pu4koff вне форума   Ответить с цитированием
Старый 13.06.2009, 16:13   #14
atomicxp
Форумчанин
 
Аватар для atomicxp
 
Регистрация: 01.05.2009
Сообщений: 111
Репутация: 63

skype: atomicxp
Печаль

Цитата:
Сообщение от pu4koff Посмотреть сообщение
Получили мы объект посредством вызова фабричного метода как указатель на интерфейс. Как тогда удалить этот объект, когда он станет ненужным?
В этом и заключается идея, запретить удалять объект через интерфейсы. В данном случае удаление возможно только с помощью вызова delete посредством указателя на объект, но не через указатель интерфейса ссылающийся на этот объект.

То есть если нужно удалять объект через интерфейсы, то можно включить виртуальный деструктор. А если не надо, то вот таким способом это запретить. Мне думается что понятие интерфейса подразумевает, что мы не будет удалять объект через интерфейсы, так как смысла в этом нет.

Ведь интерфейс создан для управления и ему лишь временно передаётся возможность управления объектом. Что будет если использовать более одного интерфейса на объекте, потом удалить одним из них объект и попытаться использоваться другой интерфейс. Будет ошибка.
atomicxp вне форума   Ответить с цитированием
Старый 13.06.2009, 17:43   #15
atomicxp
Форумчанин
 
Аватар для atomicxp
 
Регистрация: 01.05.2009
Сообщений: 111
Репутация: 63

skype: atomicxp
Лампочка Delegation pattern/Шаблон делегирования

Переходим к следующему шаблону проектирования так же принадлжащему к типу основных шаблонов (Fundamental)

* Delegation pattern/Шаблон делегирования

Оригинальничать не будем, потому сразу определение из вики:

Цитата:
Сообщение от wiki
В разработке ПО, шаблон делегирования (англ. delegation pattern) — это способ, которым объект внешне выражает некоторое поведение, но в реальности передаёт ответственность за выполнение этого поведения связанному объекту. Шаблон делегирования является фундаментальной абстракцией которая поддерживает композицию (также называемую агрегацией), примеси (mixins) и аспекты (aspects).
Та же вики сообщает о минусах
Цитата:
Сообщение от wiki
Этот шаблон обычно затрудняет оптимизацию по скорости в пользу улучшенной чистоты абстракции.
Плюсы и применимость не указана, но это и не важно, потому что данный шаблон наиболее часто используемый, так что не требует особых объяснений. Но раз уж я решил обсудить шаблоны, то придётся сделать это и для него.

Как уже было сказано, шаблон делегирования, так же известный как техника программирования включение-делегирование, ухудшает чистоту абстракций. Но здесь так же стоит отметить, что подобное негативное влияние можно сократить, а можно наоборот увеличить этот эффект. Под увеличением подразумеваются смешанные классы. Они очень сильно вредят чётким абстракциям.

Плюс заключается в возможности перестроения чужих алгоритмов под свои собственные. Таким образом можно перенести целые наборы библиотек. Именно так был построен .NET Framework, ведь рефлектор наглядно показывает, что шаблон делегирования используется в нём чуть ли не чаще, чем всё остальное. Аналогичным образом строится Mono, непроделегированные методы можно просто объявить неиспользуемыми.

Если проследить рефлектором историю изменения, то от версии 1.1 к версии 2.0 данная техника программирования стала использоваться для ухудшения абстракций самого дотнета. Хотя речь совсем не о том, в какую сторону двигается майкрософт, а о C++. Простейший пример делегирования:

Код:

#include <iostream>

using namespace std;

class ClassA
{
 public:
    void ma()
    {
        cout << "ClassA: Method A" << endl;
    }
    void mb()
    {
        cout << "ClassA: Method B" << endl;
    }
};

class ClassB
{
 private:
    ClassA* classA;
 public:
    ClassB()
    {
        classA = new ClassA();
    }

    void ma()
    {
        classA->ma();
    }
    void mb()
    {
        classA->mb();
    }
};

void Testing()
{
    ClassA* classA = new ClassA();

    classA->ma();
    classA->mb();

    ClassB* classB = new ClassB();

    classB->ma();
    classB->mb();
}

int main()
{
    Testing();

    return 0;
}

А вот более интересное использование из вики:

Код:

#include <iostream>

using namespace std;

class I {
   public:
      virtual void f ( void ) = 0;
      virtual void g ( void ) = 0;
};

class A : public I {
   public:
      void f ( void ) { cout << "A: вызываем метод f()" << std::endl; }
      void g ( void ) { cout << "A: вызываем метод g()" << std::endl; }
};

class B : public I {
   public:
      void f ( void ) { cout << "B: вызываем метод f()" << std::endl; }
      void g ( void ) { cout << "B: вызываем метод g()" << std::endl; }
};

class C : public I {
   public:
     // Конструктор
      C() : i ( new A() ) { }
     // Деструктор
      virtual ~C() {
         delete i;
      }
      void f ( void ) { i -> f(); }
      void g ( void ) { i -> g(); }
     // Этими методами меняем поле-объект, чьи методы будем делегировать
      void toA ( void ) {
         delete i;
         i = new A();
      }
      void toB ( void ) {
         delete i;
         i = new B();
      }
   private:
     // Объявляем объект методы которого будем делегировать
      I * i;
};

int main ( void ) {
   C * c = new C();

   c -> f();
   c -> g();
   c -> toB();
   c -> f();
   c -> g();

   delete c;
   return 0;
}

Данный пример намного более интересен, создаются несколько классов и благодаря переключению с помощью интерфейса появляется возможность использовать в одном объекте одними методами совершенно разную реализацию.

Конечно, недостаток в том, что приходится переключать весь класс. Так же подобных результатов можно добиться указателями на функции, а не только интерфейсами. Как бы то ни было к шаблону делегирования это не относится.

Последний раз редактировалось atomicxp; 13.06.2009 в 17:44. Причина: Delegation pattern/Шаблон делегирования
atomicxp вне форума   Ответить с цитированием
Старый 13.06.2009, 20:43   #16
atomicxp
Форумчанин
 
Аватар для atomicxp
 
Регистрация: 01.05.2009
Сообщений: 111
Репутация: 63

skype: atomicxp
По умолчанию Immutable/Неизменяемый объект

Далее по плану следует Immutable/Неизменяемый объект. Для начала нужно сказать, что неизменяемость объекта достигается различными путями. Как только объект был инициализирован, он уже не должен изменятся с точки зрения пользователя этого объекта, и не важно, чем это выражено. Объект может быть как частично, так и полностью незименямым. Иногда это достигается ключевым словом const, в других случаях закрытыми полями и методом доступа с запретом изменять значения объекта.

Простейший случай использования:
Код:

#include <iostream>

using namespace std;

class ClassA
{
 private:
    int _value; // immutable field
 public:
    ClassA(const int& value)
    {
        _value = value;
    }
 public:
    int getValue() const // immutable using
    {
        return _value;
    }
};

void Testing()
{
    ClassA* classA = new ClassA(15);
    cout << "value = " << classA->getValue() << endl;
}

int main()
{
    Testing();

    return 0;
}

Неизменямость хоть и проста в использовании, но требует более детального рассмотрения.
atomicxp вне форума   Ответить с цитированием
Старый 13.06.2009, 21:21   #17
pu4koff
Профессионал
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,639
Репутация: 3613
По умолчанию

Если добавить в объект коллекцию (массив, список,...), то уже не всё так тривиально будет. Если изменить коллекцию, то изменится ли состояние объекта? Можно ли для константного объекта изменять отдельные элементы коллекции или нет? и т.д. Но всё это будет уже зависеть от конкретной задачи
pu4koff вне форума   Ответить с цитированием
Старый 13.06.2009, 21:55   #18
atomicxp
Форумчанин
 
Аватар для atomicxp
 
Регистрация: 01.05.2009
Сообщений: 111
Репутация: 63

skype: atomicxp
Сообщение введение в стереотипы

Цитата:
Сообщение от pu4koff Посмотреть сообщение
Если добавить в объект коллекцию (массив, список,...), то уже не всё так тривиально будет. Если изменить коллекцию, то изменится ли состояние объекта? Можно ли для константного объекта изменять отдельные элементы коллекции или нет? и т.д. Но всё это будет уже зависеть от конкретной задачи
Давай тогда для примера рассмотрим для чего же выделять шаблоны проектирования, и как это поможет в реальном деле. Если бы шаблоны проектирования были слишком сильно размыты и их нельзя выделить в стереотипы, нам бы незачем было о них говорить. Взглянем на UML отображение класса, которое я сделал.



Не знаю насколько оно точно соответствует принятым понятиям, хотя и прочёл книгу про UML. Как раз эта одна из целей, которой нужно добиться, а именно чёткое соответствие графического вида и конкретной реализации. Причём дело не в детализации, графический вид может иметь её в меньшей степени, а в неукоснительном следовании уже принятым понятиям.

Стереотипы традиционно выделяются в <<>>, а # так понял означает закрытый. Стереотип <<Immutable>> в данном случае отнёс вовсе не к классу, а к методу. Иными словами шаблоны проектирования бывают разными и относятся к разным частям класса.

Поскольку уже было рассмотрено три шаблона, то возникает вопрос, можно ли комбинировать какие-либо из них. Если взять тот же интерфейс, то его стереотип был бы записан наверху, заместо слова <<stereotype>> находилось бы <<Interface>>.

А вот шаблон делегирования и неизменяемости относятся к методам, особенно если исходить, что включённые (агрегированные) объекты брать всегда используя методы, а сами объекты делать закрытыми или защищёнными. Иными словами пользоваться свойствами (присвоение или извлечение объекта с проверкой), ведь даже там где они имеют другой вид, например, .NET, на самом деле создаются методы с приставкой get/set.

Может ли в методе быть <<immutable delegation>>, очевидно да. Даже в таких размытых шаблонах проектирования можно добиться определённости. Причём как видно, шаблоны этих же категорий, а так же многих других, имеют более чёткое определение и вообще не комбинируются вместе.
atomicxp вне форума   Ответить с цитированием
Старый 14.06.2009, 18:28   #19
atomicxp
Форумчанин
 
Аватар для atomicxp
 
Регистрация: 01.05.2009
Сообщений: 111
Репутация: 63

skype: atomicxp
Сообщение Property Container/Контейнер свойств

Основные шаблоны (Fundamental)

* Delegation pattern/Шаблон делегирования
* Functional design/Шаблон функционального дизайна
* Immutable/Неизменяемый объект
* Interface
* Marker interface
* Property Container

Property Container/Контейнер свойств

Ниже представлен простейший пример с закрытым значением поля, который хранит свойство. Два метода, один называется accessor, имеет приставку get и извлекает значение. Другой называется mutator, имеет приставку set и изменяет значение.

Код:

#include <iostream>

using namespace std;

class ClassA
{
 private:
    int _value; // property field
 public:
    ClassA()
    {
        _value = 0;
    }
 public:
    int getValue() const // accessor
    {
        // get property
        return _value;
    }
    void setValue(const int& value) // mutator
    {
        // check & assignment property
        _value = value;
    }
};

int main()
{
    ClassA* classA = new ClassA();
    cout << classA->getValue() << endl;
    classA->setValue(15);
    cout << classA->getValue() << endl;

    return 0;
}

Так же стоит отметить, что в реальности данные могут хранится где угодно, не обязательно в закрытом поле, и быть в любом виде. За их проверку и перобразование отвечает accessor и mutator, в простейшем случае я не стал использовать дополнительные возможности, которые они предоставляют. В сложных случаях могут использоватся инструкции ветвления, а так же выбрасываться исключения.
atomicxp вне форума   Ответить с цитированием
Старый 14.06.2009, 19:52   #20
pu4koff
Профессионал
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,639
Репутация: 3613
По умолчанию

Таки для наглядности в "мутаторе" можно проверку какую-нибудь всеже написать:
Код:

если (value < 0) то выкинуть исключение.

Читабельность примера такой же останется, но у новичков не возникнет вопроса: "нафига вообще это надо и почему бы не сделать тупо _value public'ом?"
pu4koff вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Паттерны проектирования shinauri PHP 0 17.07.2012 17:06
Консольный текстовый редактор и паттерны delias C# (си шарп) 0 22.04.2011 00:41
паттерны для детсада pproger Общие вопросы по программированию, компьютерным наукам 4 11.04.2011 19:40
паттерны проектирования prokach Общие вопросы C/C++ 3 18.01.2011 23:23


23:33.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru