Вопрос для гуру, это - Singleton

Domovoj

Guest
Автор оригинала: Mihail
Повторюсь, я не против static переменных, но против static методов и вот одна из причин почему:

Источник http://citforum.nis.nnov.su/SE/project/pattern/p_2.shtml#3.3.2

Выдержка:
Разумнее создавать именно статический экземпляр специального класса, а не объявить требуемые методы статическими, поскольку при использовании методов экземпляра можно применить механизм наследования и создавать подклассы. Статические методы в языках программирования не полиморфны и не допускают перекрытия в производных классах.
Решение на основе создания экземпляра является более гибким, поскольку впоследствии может потребоваться уже не единственный экземпляр объекта, а несколько.
.
По-моему ты просто не понял о чём это. Там сказано, что вместо того, чтобы создавать кучу static методов, лучше создать один static объект, инкапсулирующий эти методы. Но там не сказано, что этот static объект плохо создавать через static method.
 

Mihail

Guest
При таком способе нет смысла вобще применять static методы.
Зачем?
Приведи мне пример.
 

Domovoj

Guest
Автор оригинала: Mihail
При таком способе нет смысла вобще применять static методы.
Зачем?
Приведи мне пример.
Вариант #1:
PHP:
$result = Database::execute('SELECT * FROM TEST');
$id = Database::insert('INSERT INTO TEST (a) VALUES ("A")');
и т.д.
Вариант #2
PHP:
$db = Database::getInstance();
$result = $db->execute('.....');
$id = $db->insert('....');
и т.д.
В первом случае ты не сможешь наследовать класс Database. Во втором случае работа с базой данных идёт через нормальный динамический объект, и наследовать его можно (при этом нужно переписывать только статический метод getInstance(), т.к. нет аналогии $this для статических методов, а self всегда возвращает тот класс, в котором был объявлен).
 

Mihail

Guest
Опять за старое. Не убедил.
Сделай мне связку из двух классов A и B.

class Database{
}

class B{
private static $db=NUll;

B() {
$db = Database::getInstance();
}

}

Вот это ты имел ввиду?
 

Domovoj

Guest
Автор оригинала: Mihail
Опять за старое. Не убедил.
В чём не убедил? Что у тебя не singleton? Или что твой подход неудобный?

Сделай мне связку из двух классов A и B.
Чего? не понял о какой связке ты говоришь.

class Database{
}

class B{
private static $db=NUll;

B() {
$db = Database::getInstance();
}

}

Вот это ты имел ввиду?
Я тебе привёл пример того, что имелось в виду по той ссылке, которую ты дал. Что вместо кучи статических методов лучше использовать статический (singleton) объект, который можно при необходимости наследовать и использовать преимущества полиморфизма.

То, что ты сейчас имеешь в виду мне не понятно. Зачем private static $db, если этот static $db уже есть в Database, и его возвращает getInstance()? Зачем тебе его ещё раз сохранять?
 

Mihail

Guest
Скажи, что кроме вызова функции вне объекта ты получаеш от static метода.
Я еще пойму необходимость статических переменных, но объясни мне зачем нужны статик методы. Если взять к примеру объявить обыкновенную функцию и через нее контролировать создание объекта будет тоже самое.


function& Instance() {
static $instance=Null;

if ( is_null($instance) ) {
$instance=new A();
}

return $instance;
}
 

pachanga

Новичок
static методы всего лишь нужны для обворачивания глобальных функций в некоторый namespace(не совсем удачное определение) в виде класса.

К тому же static методы могут обращаться к static аттрибутам класса, которые помечены как protected/private.

Еще есть понятие как consistency(постоянство, логичность), использование static позволяет сделать OO код более последовательным в этом смысле, без использования глобальных функций.

Что по-твоему более читабельно:
Код:
$a = getInstanceA();
или:
Код:
$a = A :: instance();
Конечно, на вкус и цвет...., но лично мне второй вариант кажется более логичным.
 

Mihail

Guest
Вам не кажется что static методы что-то из рода
goto оператора.

Без них можно обойтись, но их упорно продолжают использовать.

По поводу consistency(логичности) - static методы только внешнее в синтаксическом плане логичны.

Зато нарушают гораздо важную вещ - методы объекта не могут быть вызваны/доступны без создания объекта.

Разрушают идиологию private и protect переменных.

Зачем нужен тогда final, когда можно написать static.

И по поводу исключений.

9.5 Особые ситуации могут не быть ошибками
Если особая ситуация ожидалась, была перехвачена и не оказала плохого воздействия на ход программы, то стоит ли ее называть ошибкой? Так говорят только потому, что программист думает о ней как об ошибке, а механизм особых ситуаций является средством обработки ошибок. С другой стороны, особые ситуации можно рассматривать просто как еще одну структуру управления.
 

pachanga

Новичок
Зато нарушают гораздо важную вещ - методы объекта не могут быть вызваны/доступны без создания объекта.
Они для этого и создавались.

Разрушают идиологию private и protect переменных.
Каким образом?

Зачем нужен тогда final, когда можно написать static.
Ты понимаешь, что это совершенно разные семантические понятия?

Я лично против чрезмерного употребления static методов, но только по той причине, что из-за этого усложняется тестирование, но никак не по тем причинам, что ты привел.

-~{}~ 23.08.05 12:32:

Наверное, лучшим "лекарством" для Mihal'а будет реальное использование его версии Singleton в рабочих проектах...
 

Domovoj

Guest
Автор оригинала: Mihail
Зато нарушают гораздо важную вещ - методы объекта не могут быть вызваны/доступны без создания объекта.
Это не методы объекта. Это методы класса, обслуживающие работу объектов этого класса.

Разрушают идиологию private и protect переменных.
Это как? Ты считаешь, что если ты добавишь static методы, то private и protected переменные сразу станут public?

Зачем нужен тогда final, когда можно написать static.
Это что значит? Ты бы ещё колбасу с компотом сравнил :)
 

Profic

just Profic (PHP5 BetaTeam)
Вам не кажется что static методы что-то из рода
goto оператора.
Без них можно обойтись, но их упорно продолжают использовать.
По поводу consistency(логичности) - static методы только внешнее в синтаксическом плане логичны.
Зато нарушают гораздо важную вещ - методы объекта не могут быть вызваны/доступны без создания объекта.
Разрушают идиологию private и protect переменных.
Еще раз про static.
По-моему ты просто не понял о чём это. Там сказано, что вместо того, чтобы создавать кучу static методов, лучше создать один static объект, инкапсулирующий эти методы. Но там не сказано, что этот static объект плохо создавать через static method.
Этот текст не о том, что static это зло, а о том что его злоупотребление это зло. Почитайте классика:
10.2.4 Static Members [class.static]
The convenience of a default value for Dates was bought at the cost of a significant hidden problem. Our Date class became dependent on the global variable today. This Date class can be used only in a context in which today is defined and correctly used by every piece of code. This is the kind of constraint that causes a class to be useless outside the context in which it was first written. Users get too many unpleasant surprises trying to use such contextdependent classes, and maintenance becomes messy. Maybe ‘‘just one little global variable’’ isn’t too unmanageable, but that style leads to code that is useless except to its original programmer. It should be avoided.
Fortunately, we can get the convenience without the encumbrance of a publicly accessible global variable. A variable that is part of a class, yet is not part of an object of that class, is called a static member. There is exactly one copy of a static member instead of one copy per object, as for ordinary nonstatic
members. Similarly, a function that needs access to members of a class, yet doesn’t need to be invoked for a particular object, is called a static member function.
Here is a redesign that preserves the semantics of default constructor values for Date without the problems stemming from reliance on a global:
PHP:
class Date {
    int d, m, y;
    static Date default_date;
public:
    Date(int dd = 0, int mm = 0, int yy = 0);
    // ...
    static void set_default(int, int, int);
};
We can now define the Date constructor like this:
PHP:
Date::Date(int dd, int mm, int yy) {
    d = dd ? dd : default_date.d;
    m = mm ? mm : default_date.m;
    y = yy ? yy : default_date.y;
    // check that the Date is valid
}
We can change the default date when appropriate. A static member can be referred to like any other member. In addition, a static member can be referred to without mentioning an object. Instead, its name is qualified by the name of its class. For example:
PHP:
void f() {
    Date::set_default(4,5,1945);
}
Static members – both function and data members – must be defined somewhere. For example:
PHP:
Date Date::default_date(16,12,1770);
void Date::set_default(int d, int m, int y) {
    Date::default_date = Date(d, m, y);
}
Now the default value is Beethoven’s birth date – until someone decides otherwise.
Note that Date() serves as a notation for the value of Date::default_date. For example:
PHP:
Date copy_of_default_date = Date();
Consequently, we don’t need a separate function for reading the default date.
Зачем нужен тогда final, когда можно написать static.
Э-э-э. Мне стало интересно какими логическими потаенными тропками нужно пройти, чтобы такое сказать... Это совершенно разные вещи.

9.5 Особые ситуации могут не быть ошибками
Если особая ситуация ожидалась, была перехвачена и не оказала плохого воздействия на ход программы, то стоит ли ее называть ошибкой? Так говорят только потому, что программист думает о ней как об ошибке, а механизм особых ситуаций является средством обработки ошибок. С другой стороны, особые ситуации можно рассматривать просто как еще одну структуру управления.
Продолжение того, что вы пропустили:
14.5 Exceptions That Are Not Errors[except.not.error]
...
However, such use of exceptions can easily be overused and lead to obscure code. Whenever reasonable, one should stick to the ‘‘exception handling is error handling’’ view. When this is done, code is clearly separated into two categories: ordinary code and error-handling code. This makes code more comprehensible. Unfortunately, the real world isn’t so clear cut. Program organization will (and to some extent should) reflect that.
Error handling is inherently difficult. Anything that helps preserve a clear model of what is an error and how it is handled should be treasured.
A тут как раз говорится, что такого использования исключении следует избегать.
 

Domovoj

Guest
Автор оригинала: Profic
Еще раз про static.

Этот текст не о том, что static это зло, а о том что его злоупотребление это зло. Почитайте классика:
...
Можно узнать ссылку, где это взять? Интересно почитать...
 

Mihail

Guest
http://uic.rsu.ru/doc/programming/c++/straustrup/cpptut.html


9.5 Особые ситуации могут не быть ошибками


Если особая ситуация ожидалась, была перехвачена и не оказала
плохого воздействия на ход программы, то стоит ли ее называть
ошибкой? Так говорят только потому, что программист думает о ней
как об ошибке, а механизм особых ситуаций является средством
обработки ошибок. С другой стороны, особые ситуации можно
рассматривать просто как еще одну структуру управления. Подтвердим
это примером:

class message { /* ... */ }; // сообщение

class queue { // очередь
// ...
message* get(); // вернуть 0, если очередь пуста
// ...
};

void f1(queue& q)
{
message* m = q.get();
if (m == 0) { // очередь пуста
// ...
}
// используем m
}

Этот пример можно записать так:

class Empty { } // тип особой ситуации "Пустая_очередь"

class queue {
// ...
message* get(); // запустить Empty, если очередь пуста
// ...
};

void f2(queue& q)
{
try {
message* m = q.get();
// используем m
}
catch (Empty) { // очередь пуста
// ...
}
}

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

class queue {
// ...
message* get(); // запустить Empty, если очередь пуста
int empty();
// ...
};

void f3(queue& q)
{
if (q.empty()) { // очередь пуста
// ...
}
else {
message* m = q.get();
// используем m
}
}

Отметим, что вынести из функции get() проверку очереди на пустоту
можно только при условии, что к очереди нет параллельных обращений.
Не так то просто отказаться от взгляда, что обработка особой
ситуации есть обработка ошибки. Пока мы придерживаемся такой точки
зрения, программа четко подразделяется на две части: обычная часть
и часть обработки ошибок. Такая программа более понятна. К сожалению,
в реальных задачах провести четкое разделение невозможно, поэтому
структура программы должна (и будет) отражать этот факт. Допустим,
очередь бывает пустой только один раз (так может быть, если функция
get() используется в цикле, и пустота очереди говорит о конце цикла).
Тогда пустота очереди не является чем-то странным или ошибочным.
Поэтому, используя для обозначения конца очереди особую ситуацию,
мы расширяем представление об особых ситуациях как ошибках. С другой
стороны, действия, принимаемые в случае пустой очереди, явно отличаются
от действий, принимаемых в ходе цикла (т.е. в обычном случае).
Механизм особых ситуаций является менее структурированным,
чем такие локальные структуры управления как операторы if или for.
Обычно он к тому же является не столь эффективным, если особая
ситуация действительно возникла. Поэтому особые ситуации следует
использовать только в том случае, когда нет хорошего решения с более
традиционными управляющими структурами, или оно, вообще, невозможно.
Например, в случае пустой очереди можно прекрасно использовать для
сигнализации об этом значение, а именно нулевое значение указателя на
строку message, значит особая ситуация здесь не нужна. Однако, если бы
из класса queue мы получали вместо указателя значение типа int, то
то могло не найтись такого значения, обозначающего пустую очередь.
В таком случае функция get() становится эквивалентной операции
индексации из $$9.1, и более привлекательно представлять пустую очередь
с помощью особой ситуации. Последнее соображение подсказывает, что
в самом общем шаблоне типа для очереди придется для обозначения пустой
очереди использовать особую ситуацию, а работающая с очередью функция
будет такой:

void f(Queue<X>& q)
{
try {
for (;;) { // ``бесконечный цикл''
// прерываемый особой ситуацией
X m = q.get();
// ...
}
}
catch (Queue<X>::Empty) {
return;
}
}

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

texrdcom

Новичок
Да колесо изобрести не речку перейти ребят вы ман читали php 5 там есть реализация данного петтерна:
Singleton
The Singleton pattern applies to situations in which there needs to be a single instance of a class. The most common example of this is a database connection. Implementing this pattern allows a programmer to make this single instance easily accessible by many other objects.

Пример 19-24. Singleton Function

<?php
class Example
{
// Hold an instance of the class
private static $instance;

// A private constructor; prevents direct creation of object
private function __construct()
{
echo 'I am constructed';
}

// The singleton method
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}

return self::$instance;
}

// Example method
public function bark()
{
echo 'Woof!';
}

// Prevent users to clone the instance
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}

}

?>

This allows a single instance of the Example class to be retrieved.

<?php
// This would fail because the constructor is private
$test = new Example;

// This will always retrieve a single instance of the class
$test = Example::singleton();
$test->bark();

// This will issue an E_USER_ERROR.
$test_clone = clone($test);

?>
 

whirlwind

TDD infected, paranoid
ИМХО. Давеча тоже понадобилось... Тоже начал с конструкции

class blablabla {
private static $self = ...

в результате что получил... как только первосозданный экземпляр случайно уничтожается, вся работа летит в тартарары. это при всем том гемморе с методами, когда в каждом нужно извлечь и обратиться... я сделал проще - объявил все атрибуты класса статическими и написал для внутреннего использования приватные геттеры/сеттеры.
 

Mihail

Guest
Здесь поднята дилема:

Нужны static методы когда вполне достаточно static переменных?

В случае с Singelton - static функции позволяют сохранить синтаксическую локаничность языка. А дальше сплошняком вред, вред, вред.

Возможно, если все объекты в программе пораждаются фабрикой классов то без Singleton можно обойтись.

По поводу исключений - почитайте книги по Хакингу shareware программ. Там есть одна глава посвященная выскакивающим окошком. Суть такая - никто не обрабатывает исключения в слдучае неудачного вывода окна диалога, а команда вызова окна просто забивается nop-ами после этого окно не демонстрируется.
Вроде абсурд, проверять вызвалось окно или нет, а на самом деле очень важная вещ оказалась.

Кто знает, хватит памяти или нет для следующей операции выделения памяти? Почему же не проверять операцию new?

Все учебники по С пестрят проверками alloca, так почему же такая уверенность в PHP что память никогда не закончится?
 
Сверху