сабж — моя идея — давно её толкаю, — по моему это единственный критерий оценки хорошего проектирования
всё бы ничего и все согласны но обычно споры начинаются вокруг:
class A
{
public int a;
public void Clear1()
{
foreach(FieldInfo pi in GetType().GetFields())
{
pi.SetValue(this, 0);
}
}
public virtual void Clear2()
{
a = 0;
}
}
class AB : A
{
public int b;
public override void Clear2()
{
base.Clear2();
b = 0;
}
}
class AC : A
{
public int c;
public override void Clear2()
{
base.Clear2();
c = 0;
}
}
я считаю что код Clear1() решает задачу раз и навсегда, решает её хорошо и правильно
но есть люди которые утверждают что
а) это неочевидный код
б) хакерство и подростковый максимализм
в) рефлекшн тормозит и т.д.
и соответственно предлагают Clear2()
а вы как думаете ?
natural born flamer
Re: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>но есть люди которые утверждают что
Не перевелись еще горцы в селениях. A>а) это неочевидный код
+1 A>б) хакерство и подростковый максимализм
+1 A>в) рефлекшн тормозит и т.д.
+1
A>и соответственно предлагают Clear2()
+1
Попробуй запихни в класс какой-нибудь struct. Посмотрим что получится.
С новым годом, Gleb.
Re: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>я считаю что код Clear1() решает задачу раз и навсегда, решает её хорошо и правильно A>но есть люди которые утверждают что A>а) это неочевидный код A>б) хакерство и подростковый максимализм A>в) рефлекшн тормозит и т.д.
Соглашусь с пунктом в, а так же добавлю, что этот код:
г) не обобщенный (способен работать только с числовми свойствами)
д) расчитан на конкретный паттерн инициализации (нулем)
е) инициализация нулями бессмысленна, так как в Шарпе все члены и так инициализируеются нулями по умолчанию
ж) может пересечься с кодом в базовых классах.
A>и соответственно предлагают Clear2()
A>а вы как думаете ?
Как минимум пункт в может убить все остальные рассуждения.
... << RSDN@Home 1.1.4 beta 3 rev. 267>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: хороший код == неизбыточный код -> компактный код
Спецификация — делать то же что и компилятор когда он инициализирует экземпляры по умолчанию.
На все ваши доводы про то что это не сработает с любым не числовым мембером:
а) просто это утрированный пример. Этот код конечно не был бы написан если бы были другие спецификации — он бы им не соответствовал просто. Можно написать рекурскивный Clear1() c 3 условиями (для объектов (строк, массивов(для IDisposable можно ещё и Dispose() вызвать)) — null, для структур — рекурсия, для чисел и инамов — 0). Он будет безотказным.
б) про скорость — речь не о новом движке для квака а о бизнес приложении — заметьте — рефлекшн хоть и не быстр — памяти не ест — все возвращаемые им объекты — либо структуры в стэке либо единственные глобальные экземпляры, задержки по сравнению с созданием любого контрола на форме не будет, память копиться мусором тоже, так что аргумент несерьёзен по моему.
Спор скорее в разности подходов — мой код неочевиден для того кто не видел моего класса. С другой стороны мало есть классов в реальных приложениях кроме документированных библиотечных от которых можно наследоваться не посмотрев предварительно кода. А мой код заствляет перегружать на один метод меньше и гарантирует от ошибок типа: кто то добавил мембер, но забыл его чистить.
natural born flamer
Re[3]: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>б) про скорость — речь не о новом движке для квака а о бизнес приложении — заметьте — рефлекшн хоть и не быстр — памяти не ест — все возвращаемые им объекты — либо структуры в стэке либо единственные глобальные экземпляры, задержки по сравнению с созданием любого контрола на форме не будет, память копиться мусором тоже, так что аргумент несерьёзен по моему.
А ты представляшь какова разница между этим кодом? Тебя не покоробит если это будет 2-3 порядка?
Безнес приложения тоже ктитичные ко времени приложения. Может быть им не нужен околореалтаймный режим, но если твоя система не будет удовлетворительно работать на имещейся технике, то прийдется валить все на дотнет.
A>Спор скорее в разности подходов — мой код неочевиден для того кто не видел моего класса. С другой стороны мало есть классов в реальных приложениях кроме документированных библиотечных от которых можно наследоваться не посмотрев предварительно кода.
Это признак плохого дизайна. Наследование от некоторого класса никак не должна определяться реализацией. Скорее разумно гворить о том, что лучше наследоваться от абстрактных классов.
A> А мой код заствляет перегружать на один метод меньше и гарантирует от ошибок типа: кто то добавил мембер, но забыл его чистить.
В общем, ты выбрал плохой подход. Единственное, чего ты достиг — это автоматизации инициализации. Да еще и нулями. Нулями вообще инициализировать бессмысленно. Так же бессмысленно экономить на иерархиях из 10 классов.
Если же у вас там сотни классов, то разумным было бы создать автотатическую генерацию кода инициализации. Да и не только инициализации. В огромных иерархиях лучше весь код делать по шаблону. Иначе потом поддержка кода будет невносимо сложной.
Так что лучше создайте генератор кода. Вариантов тут множество. Можно взять за основу КодСмит, XSLT, R# или вообще генерировать код вручную на базе информации о типах из некой модельной сбрки.
Получится так же автоматически, но без жудких накладных расходов и ненужных ограничений.
... << RSDN@Home 1.1.4 beta 3 rev. 273>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: хороший код == неизбыточный код -> компактный код
а) рефлекшн тормозит в 1000 раз — сам проверял — знаю я эту проблему (на самом деле не понимаю почему он так тормозит — не так уж сложно он реализуется ведь). Повторю ещё раз — такой код медленнее и я это знаю — я не пропагандирую этот подход везде и всегда — просто в большинстве приложений если это дело не в цикле выполняется над 100000 объектами, а, допустим, чистит объект документа по команде — задержки нет никакой. Можно было бы переинициализировать объект — но тогда нарушатся ссылки на него — придётся как то это обходить или ссылаться индиректно — но проще очистить имеющийся таким универсальным алгоритмом. А теперь представьте у вас в проге десяток классов документов — все унаследованы от базового и должны иметь правильно работающий Clear(). Всё это пример опять таки — реально такой код не был никогда написан. Были похожие варианты — но они сложнее просто — их здесь разбирать долго будет.
б) Теперь к вопросу о хорошей архитектуре — вот об этом я и хотел реально поговорить. Наследование не должно зависеть от реализации базовго класса ? Т.е. вы реально берётесь утверждать что в вами спроектированных классах это так ? Если вы при наследуетесь не от интерфейса, а от класса с каким то полезным кодом внутри, то предполагается, что вы наследуетесь не только ради того чтоб каститься можно было к общему типу автоматом (для этого надо было объявить и реализовать интерфейс), а ещё и потому, что наследуете какую то реализацию, обязательно общую для всех наследников. И как же вы будете от неё НЕЗАВИСЕТЬ ?! Вы ведь специально её наследуете, а не по случаю. Не проще увидеть как работает базовый и следовать его заданной методологии создания/очистки и т.д. чем каждый раз клепать и отлаживать свою ? Я уж не говорю о том что задание жёстких ограничений в базовом классе заставит всех разработчиков классов этой иерархии писать код по одинаковой модели и соответственно более взаимно понятный.
natural born flamer
Re[5]: хороший код == неизбыточный код -> компактный код
В предложенном тобой варианте, у наследника класса A будут проблемы, если он имеет поле, которое должно быть заполнено не нулем, а каким-то другим значением (скажем, -1), в очищенном состоянии. Класс A (с методом Clear) берет на себя большую ответственность, чем должен бы: он берется очищать не только свои поля, а и поля классов наследников не имея представления о том, какой смысл они несут. Тем самым очень велик риск того, что метод Clear нарушит инвариант представления какого-нибудь наследника класса A.
A>Я уж не говорю о том что задание жёстких ограничений в базовом классе заставит всех разработчиков классов этой иерархии писать код по одинаковой модели и соответственно более взаимно понятный.
Код, написанный по одинаковой модели, не всегда легко сопровождать. Кроме того, жёсткие ограничения в базовом классе, вынуждают разработчика тыщу раз подумать прежде чем от него наследоваться -- а вдруг со временем, с приходом новых требований, его придется изменить так, что он будет нарушать эти жёсткие ограничения в базовом классе.
--
Дмитро
Re[6]: хороший код == неизбыточный код -> компактный код
ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.
ещё раз повторю — я не пропагандирую этот подход везде и всегда. если оказывается что ну никак этот метод не подходит для данного наследника — всегда можно метод объявить виртуальным и переопределить в конкретном классе — это красоты не нарушит совсем. В 99% он прекрасно подойдёт и таким.
natural born flamer
Re[7]: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.
А если мне нужна булевская переменная в начальном состоянии true ?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[8]: хороший код == неизбыточный код -> компактный код
Здравствуйте, AndrewJD, Вы писали:
AJD>Здравствуйте, antidogm, Вы писали:
A>>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.
AJD>А если мне нужна булевская переменная в начальном состоянии true ?
Здравствуйте, antidogm, Вы писали:
A>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.
Хороший и достаточно часто встречающийся подход. Например, номер итема в массиве.
С уважением, Gleb.
Re[8]: хороший код == неизбыточный код -> компактный код
A>>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы. GZ>Хороший и достаточно часто встречающийся подход. Например, номер итема в массиве.
а) ага — щас — если все массивы в чистом документе по нулям то о каком массиве речь ? о каком нить глобальном ? почему ваш объект документа должен хранить индекс чего то во внешнем массиве ? ваш объект документа самоценен по идее и левых ссылок в нём быть не должно. он ведь может быть открыт на любой системе и что это за массив который везде одинаковый есть ? если это ссылка на какой либо объект стиля или формата то это скорее должен быть идентификатор этого объекта в виде гуида или ключа в базе, но не zero-based индекс.
б) но даже если всё так плохо и без -1 вам не жить — как это обойти показано — тот же override
natural born flamer
Re[5]: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>б) Теперь к вопросу о хорошей архитектуре — вот об этом я и хотел реально поговорить. Наследование не должно зависеть от реализации базовго класса ? Т.е. вы реально берётесь утверждать что в вами спроектированных классах это так ? Если вы при наследуетесь не от интерфейса, а от класса с каким то полезным кодом внутри, то предполагается, что вы наследуетесь не только ради того чтоб каститься можно было к общему типу автоматом (для этого надо было объявить и реализовать интерфейс), а ещё и потому, что наследуете какую то реализацию, обязательно общую для всех наследников. И как же вы будете от неё НЕЗАВИСЕТЬ ?! Вы ведь специально её наследуете, а не по случаю. Не проще увидеть как работает базовый и следовать его заданной методологии создания/очистки и т.д. чем каждый раз клепать и отлаживать свою ? Я уж не говорю о том что задание жёстких ограничений в базовом классе заставит всех разработчиков классов этой иерархии писать код по одинаковой модели и соответственно более взаимно понятный.
У меня каждый класс владеет своей функциональностью и данными. При этом базовый класс, никогда не имеет прямого доступа к данным потомка. Иначе:
1. Хрен потом кто-то поймет, а где-же выполняется та, или иная функциональность.
2. Обязательно, попадется класс который выходит за пределы данной универсальности.
В твоем случае, оба пункта не выполняется. У меня, на каждый класс, можно сказать и выписать какую функциональность он выполняет. Притом, независимо участвует ли он в наследовании, или нет. И если мне понадобится изменить обработку данных в отдельном потомке (а это самая частая операция), я всегда знаю где это надо делать. В некоторых кругах, это называется инкапсуляция.
С уважением, Gleb.
Re[9]: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>а) ага — щас — если все массивы в чистом документе по нулям то о каком массиве речь ? о каком нить глобальном ? почему ваш объект документа должен хранить индекс чего то во внешнем массиве ? ваш объект документа самоценен по идее и левых ссылок в нём быть не должно. он ведь может быть открыт на любой системе и что это за массив который везде одинаковый есть ? если это ссылка на какой либо объект стиля или формата то это скорее должен быть идентификатор этого объекта в виде гуида или ключа в базе, но не zero-based индекс.
Для индекса в массиве (даже если он не инициализирован) нормальное значение -1 (или другое которое даже теоретически не может присутствовать). Иначе вы наложите обязательство на программиста (который будет вести код после вас). До тех пор, пока он не поймет данную правду жизни, поминать будет матерком.
A>б) но даже если всё так плохо и без -1 вам не жить — как это обойти показано — тот же override
Потом, фиг найдешь, где это инициализируется. Функциональность сильно размазана.
С уважением, Gleb.
Re: хороший код == неизбыточный код -> компактный код
Здравствуйте, antidogm, Вы писали:
A>я считаю что код Clear1() решает задачу раз и навсегда, решает её хорошо и правильно A>но есть люди которые утверждают что A>а) это неочевидный код A>б) хакерство и подростковый максимализм A>в) рефлекшн тормозит и т.д.
A>а вы как думаете ?
По-моему, куда правильнее не очищать объект, а пересоздавать заново — с помощью
конструктора. Таким образом, переменные будут установлены в значения по умолчанию,
если они явно не проинициализированы в конструкторе, и в нужные значения, если проинициализированы.
Никаких неочевидностей, хакерства, рефлекшена — и никакого лишнего кода.
Задача решена — УРА ! — землекопа полтора !
Re[6]: хороший код == неизбыточный код -> компактный код
GZ>1. Хрен потом кто-то поймет, а где-же выполняется та, или иная функциональность.
Опять тезис о том что кто то не посмотрит на предка решив передлать потомка.
На этот тезис я уже отвечал тем что если у предка наследуется какая то функциональность (тот же Clear()) то не смотреть как оно устроено вообще чревато. Иначе откуда вам знать какие значения у полей класса после вызова Clear() как бы и кем бы он не был написан ? Ведь название метода вам этого не скажет ! Или вам наплевать на значения тех полей которые вам достались от базового класса ? Зачем же вы от него наследовались тогда ?
GZ>2. Обязательно, попадется класс который выходит за пределы данной универсальности.
Супер — как это обойти я уже показал — о-вер-райд.
GZ>В твоем случае, оба пункта не выполняется.
я оспорил оба пункта а этот тезис не имеет ценности сам по себе
GZ>У меня, на каждый класс, можно сказать и выписать какую функциональность он выполняет. Притом, независимо участвует ли он в наследовании, или нет.
а кто сказал что в этой схеме нельзя ? класс А отвечает за инициализацию и реинициализацию и задаёт дефолтные универсальные методы для этого которые можно переопределить при необходимости.
GZ>И если мне понадобится изменить обработку данных в отдельном потомке (а это самая частая операция), я всегда знаю где это надо делать.
Что касается изменения схемы реинициализации — правильно — в переопределённом методе Clear() — я тоже знаю. А что касается остальных методов — то они вообще не при чём.
GZ>В некоторых кругах, это называется инкапсуляция.
Наследование реализации нарушает инкапсуляцию потомка по любому. Ибо филды предка являются и филдами потомка тоже, и методы предка без зазрения совести их используют наравне с методами потомка. Суть наследования реализации в отличие от наследования интерфейса в реюзе однажды написанного правильного кода который задаёт какие то схемы поведения а не просто набор методов — и чем больше реюз — тем больше пользы — иначе наследоваться зачем ? В моей схеме реюз больше — очевидно ?!
По моему вы к иерархии классов относитесь так же как к просто набору классов реализующих те или иные (иногда общие) интерфейсы — и кстати это популярная сегодня точка зрения — есть мол компоненты есть интерфейсы, а наследование суть от лукавого. Но это скорее точка зрения архитектора который вам весело расчертит что вон тот то отвечает за это и на этом его работа закончена.
Я же пытаюсь извлечь выгоду из того, что это именно иерархия. И кроме того что задаю набор методов в предке ещё и пытаюсь задать стратегию написания потомков. И чем более жёстко я это сделаю — тем более вероятно что их напишут единообразно и они будут работать так как от них ожидал я когда писал предка.
GZ>С уважением, Gleb.
Не надо меня уважаеть, вы меня ещё не знаете
natural born flamer
Re[2]: хороший код == неизбыточный код -> компактный код
IVN>По-моему, куда правильнее не очищать объект, а пересоздавать заново — с помощью IVN>конструктора.
В "Re[4]:" я уже объяснял что это схематический пример и упомянул то решение какое вы предлагаете — я с ним в принципе согласен — но есть одно но — оно вынуждает потом либо обновить все ссылки на этот объект у всех вокруг — либо изначально всем иметь ссылки не на объект а на какой то контейнер который будет возвращать уже реальную ссылку, либо ссылаться на объект по ключу ну и т.д.
natural born flamer
Re[10]: хороший код == неизбыточный код -> компактный код
GZ>Для индекса в массиве (даже если он не инициализирован) нормальное значение -1 (или другое которое даже теоретически не может присутствовать). Иначе вы наложите обязательство на программиста (который будет вести код после вас). До тех пор, пока он не поймет данную правду жизни, поминать будет матерком.
я бы реализовал следующим образом это:
ArrayList _items;
object _selectedItem;
IList Items
{
get
{
if(_items == null)
{
_items = new ArrayList();
}
Здравствуйте, antidogm, Вы писали:
GZ>>1. Хрен потом кто-то поймет, а где-же выполняется та, или иная функциональность.
A>Опять тезис о том что кто то не посмотрит на предка решив передлать потомка. A>На этот тезис я уже отвечал тем что если у предка наследуется какая то функциональность (тот же Clear()) то не смотреть как оно устроено вообще чревато.
Наиболее правильно, если пользователь вашего класса, сможет не смотреть на реализацию. (см об ООП). A>Иначе откуда вам знать какие значения у полей класса после вызова Clear() как бы и кем бы он не был написан ? Ведь название метода вам этого не скажет !
Название виртульного метода Clear вам ни о чем не говорит? Чаще всего, название метода достаточно для того чтобы понять что он делает. A>Или вам наплевать на значения тех полей которые вам достались от базового класса ? Зачем же вы от него наследовались тогда ?
Если готовить по правильному, то наплевать. (см об ООП). Я работаю с поведением объектов, а не значениями его полей. Пускай о значениях думает сам этот класс, это его пререгатива.
GZ>>2. Обязательно, попадется класс который выходит за пределы данной универсальности.
A>Супер — как это обойти я уже показал — о-вер-райд.
Про override см. про ООП. Код получается с частными случаями.
GZ>>В твоем случае, оба пункта не выполняется.
A>я оспорил оба пункта а этот тезис не имеет ценности сам по себе
Ну-ну
GZ>>У меня, на каждый класс, можно сказать и выписать какую функциональность он выполняет. Притом, независимо участвует ли он в наследовании, или нет.
A>а кто сказал что в этой схеме нельзя ? класс А отвечает за инициализацию и реинициализацию и задаёт дефолтные универсальные методы для этого которые можно переопределить при необходимости.
Класс А не может отвечать за инициализацию не себя, и реинициализацию. Ты же сам описал наличие многих частных случаев с override.
GZ>>И если мне понадобится изменить обработку данных в отдельном потомке (а это самая частая операция), я всегда знаю где это надо делать.
A>Что касается изменения схемы реинициализации — правильно — в переопределённом методе Clear() — я тоже знаю. А что касается остальных методов — то они вообще не при чём.
Clear всего лишь частный случай таких же методов.
GZ>>В некоторых кругах, это называется инкапсуляция.
A>Наследование реализации нарушает инкапсуляцию потомка по любому. Ибо филды предка являются и филдами потомка тоже, и методы предка без зазрения совести их используют наравне с методами потомка. Нарушает инкапсуляцию только программист. У тебя же есть метод инкапсулировать филды через private и создание пропертей. Думаешь, зря это сделали? Но самое интересное, ты нарушаешь инкапсуляцию потомка. A>Суть наследования реализации в отличие от наследования интерфейса в реюзе однажды написанного правильного кода который задаёт какие то схемы поведения а не просто набор методов — и чем больше реюз — тем больше пользы — иначе наследоваться зачем ? В моей схеме реюз больше — очевидно ?!
Да, но между несколькими байтами кода, и общей понятностью интерфейса, я выбираю второе. Первое всегда дороже обходится. К тому же, это отношения к фальшивой черепице не имеет.
A>По моему вы к иерархии классов относитесь так же как к просто набору классов реализующих те или иные (иногда общие) интерфейсы — и кстати это популярная сегодня точка зрения — есть мол компоненты есть интерфейсы, а наследование суть от лукавого. Но это скорее точка зрения архитектора который вам весело расчертит что вон тот то отвечает за это и на этом его работа закончена.
Покажите мне на такого архитектора пальцем. Который не знает что такое функциональная декомпозиция.
A>Я же пытаюсь извлечь выгоду из того, что это именно иерархия. И кроме того что задаю набор методов в предке ещё и пытаюсь задать стратегию написания потомков. И чем более жёстко я это сделаю — тем более вероятно что их напишут единообразно и они будут работать так как от них ожидал я когда писал предка.
А зачем так жестко? Ты думаешь только о себе. И вообще, не понял в чем состоит единообразие.
Ну и наконец, об ООП.
Когда-то, когда я был очень молод, и у меня тоже была бабушка, несколько очень умных людей задумались: А какого фига нам не выдумать ООП. Одна из проблем (я бы сказал основная) была в том, что программное обеспечение уже не могло разрабатываться только одной фирмой. Возникла проблема распространения приложений. И тогда появился ООП. Что он дал: абстракцию, инкапсуляцию, полиморфизм и наследование. Все четыре вещи, работают над данной проблемой. Допустим, одна фирма разработала библиотеку классов (например MFC), другая фирма N решила воспользоваться данной реализацией. Нужны ли ей исходники? Не обязательно. Нужно только описание (например h файлы + hlp) и реализация (lib или dll). И это хорошо. Допустим, программисту нужно освобождать некоторые данные. Смотрим на наследуемый класс, видим виртуальный метод DeleteContent. Переопределяем его. И очищаем данные, но например не все, а те которые не являются константными. Вуаля. Базовый класс не знает что мы делаем, и мы не знаем что делает базовый класс. Просмотр реализации (а это копание в нескольких десятках файлов с исходниками) и даже просмотр hlp не понадобился. Но рад этому не только пользователь, этому рада и Necrosoft. MFC еще начинался на Win16, и нормально перекочевал на Win32, плюс к этому переработан в VC7. Однако пользователю, не пришлось переписывать свою программу и сидеть на одной и той-же версии, посколько почти все изменения происходили внутри библиотеки. Ему оставалось только платить денюшку за новые возможности (мне бы так платили ). И это несмотря на то, что библиотека вся построена на наследовании. Вот это, и называется правильная инкапсуляция. Но есть в этом, одно больное место. И оказывается, что наследование подразумевает не только удобный способ работы полиформизма и реюзинга кода, но и нарушение инкапсуляции. Вот тут, и возникли сложности в том, что возможно не только построить правильную программу, но и в том, что можно сильно испортить функциональность используемого класса. Я не являюсь сторонником запрещения наследования из-за данной причины, поскольку она общеизвестна, и не стоит наступать на грабли. К тому же, практически в каждом ОО языке есть пути обхода. Объект должен быть разумно инкапсулирован не только от внешних объектов, но и от класса предка или класса потомка. Вот тогда, пользователь класса ничего не сможет испортить и навредить. И себе, и мне.
Существует, еще некоторые грабли. Они состоят в том, что если я делаю реализацию, то мне про нее все известно. И гори все синим пламенем, главное это работает и я знаю как. Но потом, программист переходит на другую работу, приходит новый программист, и после некоторого мытарства по чужому коду, он понимает что легче переписать все заново, чем просто разобраться в том, что здесь написано. А для того, чтобы он сразу врубился в код, нужно просто выполнять некоторые простые но действенные правила. В том числе инкапсуляцию и правильные названия методов и свойств.
GZ>>С уважением, Gleb.
A>Не надо меня уважаеть, вы меня ещё не знаете
С рождеством, Gleb.