Замечаю что многие студенты вместо того чтобы писать программу сами, переписывают ее у соседа с экрана. Я не возражаю - если хочется работать секретарем/секретаршей, то почему не поучиться быстро набирать на клавиатуре текст? Но какое это отношение имеет к программированию понять не могу.
Представил себе занятия по плаванию - стою я на суше, махаю руками, делаю точно также как тот, который в воде барахтается... Интересно - научусь или нет? Что-то сомнительно.... Или в качалке - один потеет, железки таскает, другой повторяет движения... Возможно даже какой-то результат и будет, но совсем не такой, как у того, который сам.
Мой совет - пишите код сами. Лучше взять задачку попроще и сделать ее. Потом взять сложнее, потом еще сложнее... Ни кто же не гонит, не торопит. Зачем хватать очень сложную задачу, понимая что ее не выполнить и этим оправдывать свое бездействие.
В той же качалке - берем сразу огромный вес, который придавит. Зовем здоровенного качка, просим "подними за меня, я не могу". Ну он-то понятно поднимет, может даже и не вспотеет, здоровый он. А вам-то что с этого толку? Даже морального удовольствия нет...
Wednesday, May 4, 2011
Tuesday, May 3, 2011
Thursday, March 17, 2011
Снова про code style...
Еще раз хочу про стиль кода написать. Замучился доказывать, что писать надо в едином стиле. Вот если кино начинается комедией, а заканчивается детективом, все плюются… Если в часть главы в книге написано от первого лица, а потом резко так, без перехода от третьего – странно все это выглядит. Возникает вопрос что курил автор. А если код так писать, почему-то нормально.
Второй вопрос – заглавные буквы. Заглавная буква это начало мысли, начало чего-то большого, обозначение идеи. Название городов пишут с большой буквы, имена людей и т.д. Но если взять и Просто так начать Писать часть слов Не понятно зачем писать с Большой буквы, то читать это сложно. Ну и про автора такого текста мысли какие-то бродят.. Так почему нужно писать имена переменных именно так:
private int MyTempVar;
Почему с большой буквы-то? Имя метода (имя человека, города) – это понятно. А тут-то зачем? И читать такой код сложно, хотя можно конечно.
Вообще загадочно, почему то что в обычной жизни никто не делает, в программировании считается нормальным и до хрипоты спорят что можно и так.
Friday, March 4, 2011
Диалоги
Индус (и) разговаривает с боссом (б) в европейской фирме:
б: Is it done?
и: Yes, but not yet.
б: so did you have chance to complete it?
и: yes
б: could you please send it to me
и: I will send it to you tomorrow after it will be finally completed
- Дим, ты все сделал по этой задаче?
- Да, все
- Совсем все или еще что-то осталось?
- Ну тут еще немного...
б: Is it done?
и: Yes, but not yet.
б: so did you have chance to complete it?
и: yes
б: could you please send it to me
и: I will send it to you tomorrow after it will be finally completed
- Дим, ты все сделал по этой задаче?
- Да, все
- Совсем все или еще что-то осталось?
- Ну тут еще немного...
События
События (event) это почти делегаты, только используется ключевое слово event, что позволяет редактору Visual Studio правильно распределять их по закладкам окна свойств.
Описание класса, использующего события:
namespace EventTest
{
/// <summary>
/// Тип метода
/// </summary>
public delegate void Progress(int progress);
public class Parser
{
/// <summary>
/// Описываем событие
/// </summary>
public event Progress ProgressHandler;
/// <summary>
/// Основной метод
/// </summary>
public void Calc()
{
for (int i = 0; i < 100; i++)
{
// Если обработчик задан - вызываем его
if (ProgressHandler != null)
ProgressHandler(i+1);
}
}
}
}
Использование этого класса:
namespace EventTest
{
class Program
{
static void Main(string[] args)
{
// Создаем экземпляр
Parser parser = new Parser();
// Вешаем обработчик
parser.ProgressHandler += new Progress(parser_ProgressHandler);
// Можно и два метода обработки одного события
parser.ProgressHandler+=new Progress(parser_ProgressHandlerSecond);
// Можно описывать обработчики "по месту", хотя это не всегда удобно
parser.ProgressHandler+= delegate(int progress)
{
Console.WriteLine("inline:" + progress);
};
// Вызываем метод
parser.Calc();
}
/// <summary>
/// Этот метод будет вызываться при обработке события
/// </summary>
static void parser_ProgressHandler(int progress)
{
Console.WriteLine("first:" + progress);
}
/// <summary>
/// Можно вешать и два метода
/// </summary>
static void parser_ProgressHandlerSecond(int progress)
{
Console.WriteLine("second:" + progress);
}
}
}
Saturday, February 26, 2011
Подклассы или типы
В пятницу на очередном занятии возник вопрос - когда лучше делать подклассы, а когда можно обойтись просто свойством (например, сделать тип сущности)? Я так думаю, что если отличий в разных типах не много, то мутить с подклассами не стоит.
Например, если кирпичи в игре Арканоид отличаются только цветом и числом попаданий до уничтожения, то вполне можно обойтись либо типом и тогда возвращать соответсвующие свойства в зависимости от типа:
public Color Foreground()
{
swith (type)
{
case StoneType.One: return Colors.Red;
............
}
Либо вообще вынести эти параметры в конструктор и типы не заводить:
public Stone(Color foreground, int countStrike)
{
.....
}
А вот если отличий будет очень много, то класс будет замусорен кучей if или switch. Вот тогда имеет смысл делать подклассы и разносить логику и код. Разумеется, если какой-то из "типов" имеет дополнительные свойства, то это однозначно нужно выностить в подкласс.
Например, если кирпичи в игре Арканоид отличаются только цветом и числом попаданий до уничтожения, то вполне можно обойтись либо типом и тогда возвращать соответсвующие свойства в зависимости от типа:
public Color Foreground()
{
swith (type)
{
case StoneType.One: return Colors.Red;
............
}
Либо вообще вынести эти параметры в конструктор и типы не заводить:
public Stone(Color foreground, int countStrike)
{
.....
}
А вот если отличий будет очень много, то класс будет замусорен кучей if или switch. Вот тогда имеет смысл делать подклассы и разносить логику и код. Разумеется, если какой-то из "типов" имеет дополнительные свойства, то это однозначно нужно выностить в подкласс.
Monday, February 21, 2011
Еще пример про делегаты
Задача такая: по имени функции (математической) получить результат ее вычисления. Самый простой вариант такой:
public class CallFunc1
{
/// <summary>
/// Вызываем функцию по имени
/// </summary>
public double GetFuncValue(string funcName, double arg)
{
switch (funcName.ToUpper())
{
case "SIN": return Math.Sin(arg);
case "COS": return Math.Cos(arg);
case "TAN": return Math.Tan(arg);
case "SQRT": return Math.Sqrt(arg);
}
throw new ArgumentException("Такой функции нет в списке зарегистрированных функций", funcName);
}
}
Но тут мы вспоминаем, что квадратный корень нельзя вычислять от отрицательного значения и добавляем еще код:
case "SQRT":
if (arg < 0)
throw new ArgumentException("Попытка вычислить квадратный корень от отрицательного числа", "arg");
return Math.Sqrt(arg);
Потом появляются еще функции и свои проверки… В результате метод GetFuncValue напоминает сборную солянку. А хотелось бы как-то попроще и покрасивее сделать.
С помощью делегатов можно сделать так. Описываем делегат, имеющий сигнатуру метода с одним параметром:
// Делегат- математический метод
public delegate double MathFunction(double arg);
А теперь описываем словарь соответствия названий и делегатов таких методов:
// Список функций
private Dictionary<string, MathFunction> funcList;
Инициализировать его нужно будет в конструкторе:
/// <summary>
/// Конструктор
/// </summary>
public CallFunc1()
{
// Создаем список функций
funcList = new Dictionary<string, MathFunction>();
funcList.Add("SIN", delegate(double arg) {
return Math.Sin(arg);
});
funcList.Add("COS", delegate(double arg)
{
return Math.Cos(arg);
});
funcList.Add("TAN", delegate(double arg)
{
return Math.Tan(arg);
});
funcList.Add("SQRT", delegate(double arg)
{
if (arg < 0)
throw new ArgumentException("Попытка вычислить квадратный корень от отрицательного числа", "arg");
return Math.Sqrt(arg);
});
}
Обратите внимание, что реализация делегата сделана прямо “по месту” (это называется анонимными методами – методами без имени).
А с помощью LINQ вызов станет совсем простым делом:
public double GetFuncValue(string funcName, double arg)
{
// Ищем нужную функцию в списке
var func = funcList.Where(f => f.Key == funcName).Select(f => f.Value).FirstOrDefault();
// Не нашли - генерируем исключение
if (func == null)
throw new ArgumentException("Такой функции нет в списке зарегистрированных функций", funcName);
// Нашли - вызываем эту функцию
return func(arg);
}
Теперь каждое имя функции связанно со своей реализацией и своими ограничениями.
Subscribe to:
Posts (Atom)