Программирование на C++

10 способов прострелить себе ногу

Создание веб приложений

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

Подпись для третьего не придумал

Американец изнасиловал лошадь, потому что думал, что у них родится кентавр

Помощь обездоленным якутам на дальнем севере

Благотворительность (на правах рекламы)

воскресенье, 22 декабря 2013 г.

Решение задач с Regex.One (с объяснениями)


С первого взгляда Регулярные выражения (Regex) могут показаться очень непонятными и сложными, поэтому после теоретического материала, лучше обязательно попрактиковаться на реальных примерах и упражнениях.
Лично для меня источником таких упражнений является сайт:
Прежде чем читать мои попытки пройти там задания, вам лучше самостоятельно пройти их, задания там очень легкие, если честно :)
Решение будет скоро, примерно через неделю )

Решение:

Первое задание: Letters

  • abcdefg
  • abcde
  • abc
Видно, что 3 буквы повторяются во всех трех строках abc, поэтому можно применить тупо выражение : 
abc
но вдруг нам надо 3 буквы, которые будут стоять рядом по алфавиту, то мы используем:
[a-c]{3}
То есть в этот паттерн будут входить abc, bac, cab итд. [a-c] означает группу, а {3} - то что букв всего 3.
\w{3} - любая буква, цифра или подчеркивание 3 раза

Второе задание: Digits


  • abc123xyz
  • define “123”
  • var g = 123;
Видно, что повторяются 3 цифры 123:
123 - если явно 3 цифры
\d{3} - цифры 3 раза
\w{3} - более нестрогое, если еще и буквы и _
[1-3]{3} - {123, 321, 213 итд (аналог \d{3} }

Третье задание: the Dot

Здесь уже сложнее, так как есть паттерн который НЕ НАДО выбирать

  • match text cat.
  • match text 896.
  • match text ?=+. 
  • skip text abc1
Видно, что здесь в каждом примере повторяется символ точка и перед точкой какие-то другие символы, но нельзя забывать, что в регексах есть оператор точка!, а если мы хотим найти символ точку, то нужно использовать слэш. Слэш экранирует символ.
.{3}\.
"." - любой символ {3} раза
"\." - поиск точки
По идее можно использовать точку вот так:
\.

Четвертое задание: Matching specific characters


  • match text can
  • match text man
  • match text fan
  • skip text dan
  • skip text ran
  • skip text pan
Видно, что регекс должен содержать c,m,f первым символом и не содержать d,r,p, используем группировку:
[cmf]an

Пятое задание: Excluding specific characters

  • match text hog 
  • match text dog
  • skip text bog
Здесь мы должны исключить символ b, это используется с помощью спецсимвола ^. Отрицание работает ТОЛЬКО в КВАДРАТНЫХ СКОБКАХ.
[^b]og
Также по заданию можно было использовать предыдущую технику:
[hd]og

Шестое задание: Character ranges

  • match text Ana
  • match text Bob
  • match text Cpc
  • skip text aax
  • skip text bby
  • skip text ccz
Ну решение состоит в группировке, здесь я думаю все понятно:
[A-C][nop][a-c]

Седьмое задание: Catching some zzz's


  • match text wazzzzup 
  • match text wazzzup
  • skip text wazup
Оч хороший пример, видно, что wazzz повторяется в двух примерах, но в некоторых жизненных ситуациях z может повторяться и больше 3ех раз, поэтому лучше использовать квантификаторы, они обозначаются обычно в фигурных скобках:
waz{3}z?up
z{3} //значит, что z может повторяться только 3 раза
z? //значит, что z может повторяться от 0 до 1 раза. (можно заменить на {0,1}
waz{3}z{0,1}up
Более лаконично:
waz{2,4}up

Восьмое задание: Mr Kleene


  • match text aaaabcc
  • match text aabbbbc
  • match text aacc
Как обычно группировка:
a{2,4}b{0,}c{1,2}
Но это не лаконично:
[abc]+ //Плюс значит один или более {1,} - эквивалент
Совсем не лаконично:
a*b*c*

Девятое задание: Characters Optional


  • match text 1 file found?
  • match text 2 files found?
  • match text x files found?
Хм, мы можем использовать логический оператор или ("|") и применить к нему квантификатор от 0, потому что число может быть и двухзначным и трехзначным итд.
К тому же на конце file может быть s или не может.
И нельзя забывать, что "?" - метасимвол, его нужно экранировать.
(\d|x){0,} files? found\?

Десятое задание: All this whitespace



  • match text 1.      abc
  • match text 2.           abc
  • match text 3.                    abc
  • skip text 4.abc

Увы, здесь пробелы при копировании не отобразились но суть в том, что нужно использовать метасимвол \s который обозначает пробел
\d\.\s{1,}abc

Одиннадцатое задание: Starting and ending



  • match text Mission: successful
  • skip text Last Mission: unsuccessful
  • skip text Next Mission: successful upon capture of target


Здесь в этом задании надо использовать символы окончания и начала строки (^ - начало и $ - конец).
^M - первая строка начинается с M
^[^LN] - первая строка не начинается с L или N
\ssuccessful$ - так как перед successful пробел, successful - идет в конце
\bsuccessful$ - \b - разделитель между словами

Двенадцатое задание: Match Groups


your task text capture
capture text file_a_record_file.pdf       (file_a_record_file)
capture text file_yesterday.pdf            (file_yesterday)
skip text testfile_fake.pdf.tmp
Суть в том, что нужно чтобы результатом выборки были строки в скобке. Делать это надо через механизм запоминающих скобок: "( )"

(file.*)\.pdf$
Видно, что на конце должно быть расширение .pdf, поэтому ставим знак окончания строки. Потом в запоминающих скобках выражение, которое содержится во всех строках. Запоминающие скобки помогают возвратить результат работы регекса.

Тринадцатое задание: Nested Groups


capture text Jan 1987 (Jan 1987, 1987)
 capture text May 1969 (May 1969, 1969)
 capture text Aug 2011 (Aug 2011, 2011)

Суть в том, что мы должны использовать ВЛОЖЕННЫЕ запоминающие скобки.
Например мы хотим захватить все содержимое, мы делаем в скобках (.*) - это захватит к примеру всю строку Jan 1987, плюс мы хотим еще вывести год, тогда мы добавляем в скобках еще скобки
(.*(\d{4}))
Еще более точно:
(\w+\s(\d{4}))

Четырнадцатое задание: More Work Group

(\d+)x(\d+)

15
I love (cats|dogs)
16

пятница, 20 декабря 2013 г.

Типаж (traits) в PHP



Новая фича, которая появилась с бетой PHP 5.4, называется Трейт (Типаж).
Трейт - единица повторного использования кода.

Используется для реализации множественного наследования, так то можно и с помощью повторного кода это сделать, но это неправильно, так как идет усложнение кода, а здесь просто все делается в одну строчку.

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

Совет для лучшего понимания и осмысления трейтов:
Это просто копипаст, то есть как будто в классе взяли и сделал include 'some.php' с каким то методом.

Еще информацию можно найти здесь:
http://habrahabr.ru/post/130000/ 
http://www.php.net/manual/ru/language.oop5.traits.php

Правила:

  • Трейт нельзя инстанцировать в какой-то объект (сначала надо добавить его в класс). 
  • В трейт можно добавлять и методы и переменные. 
  • Классы могут сколько угодно содержать трейтов. 
  • Трейт может содержать другие трейты 
  • Если разные классы будут использоват трейт со статическим свойством, то значение этого свойства будет разное. 
  • В отличие от обычного наследования. 
  • В типаже можно объявлять статические методы, но нельзя объявлять статические свойства. Но это можно обойти. 

1. Синтаксис

Трейт похож на класс, его объявление начинается со слова trait:

trait TSingleton {
  private static $_instance = null;

  public static function getInstance() {
    if (null === self::$_instance)
    {
      self::$_instance = new self();
    }

    return self::$_instance;
  }
}
class FrontController {
  use TSingleton;
}


// Также может быть использован в уже унаследованном классе
class WebSite extends SomeClass {
  use TSingleton;
}

2. Класс может также содержать неограниченное количество трейтов

(пример взят с википедии), трейты указываются через запятую:

// Шаблон
trait TBounding {
  public $x, $y, $width, $height;
}
trait TMoveable {
  public function moveTo($x, $y) {
    // ...
  }
}
trait TResizeable {
  public function resize($newWidth, $newHeight) {
    // ...
  }
}

// Несколько трейтов
class Rectangle {
  use TBounding, TMoveable, TResizeable; 
 
  function fillColor($color) {
    // ...
  }
}

3. Трейт может содержать другие трейты:

trait HelloWorld
{
    use Hello, World;
}
class MyWorld
{
    use HelloWorld;
}

4. Трейты и порядок выполнения.

Не стоит забывать, что:

1)Сначала:
Методы трейта переписывают унаследованные методы родительского класса
2)Потом уже:
Методы определенные в текущем классе переписывают методы из трейта

trait Hello
{
    function sayHello() {
        return "Hello";
    }
    function sayWorld() {
        return "Trait World";
    }
    function sayHelloWorld() {
        echo $this->sayHello() . " " . $this->sayWorld();
    }
    function sayBaseWorld() {
        echo $this->sayHello() . " " . parent::sayWorld();
    }
}
class Base
{
    function sayWorld(){
        return "Base World";
    }
}
class HelloWorld extends Base
{
    use Hello;
    function sayWorld() {
        return "World";
    }
}
$h =  new HelloWorld();
$h->sayHelloWorld(); // Hello World
$h->sayBaseWorld(); // Hello Base World

Объяснение:
Мы имеем результат Hello World, так как у нас в текущем классе (производном) определен метод, который ПЕРЕКРЫВАЕТ метод из трейта.
Поэтому,если мы хотим, чтобы HelloWorld объект выводил также Base World, нам необходимо использовать ключевое слово ::parent.

5. Конфликт имен

Может возникнуть ситуация, что два трейта содержат функцию с одинаковым именем, тогда PHP выкинет fatal error ошибку

trait Game
{
    function play() {
        echo "Playing a game";
    }
}
trait Music
{
    function play() {
        echo "Playing music";
    }
}
class Player
{
    use Game, Music;
}
$player = new Player();
$player->play();

Решение:
Нужно использовать ключевое слово instead:

class Player
{
  use Game, Music {
       Music::play insteadof Game;
  }
}
$player = new Player();
$player->play(); //Выведет: Playing music

Категория отличие от обычного наследования: 

6. Статические свойства в трейтах

Как мы помним, в наследовании, если наследуется класс со статическим свойством, то это статическое поле содержит одно и то же значение, в трейтах не так, класс в трейтах использует разные объекты;

Пример на родительских классах:

class TestClass {     
    public static $_bar; 
} 
class Foo1 extends TestClass { } 
class Foo2 extends TestClass { }
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World'; 
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Выведет: World World
Пример с использованием трейта:

trait TestTrait {     
    public static $_bar; 
} 
class Foo1 {     
    use TestTrait; 
} 
class Foo2 {    
    use TestTrait; 
}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World'; 
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Выведете: Hello World

7. Доступ из трейта к свойствам наследуемого класса:

Трейт иммет доступ к свойствам класса, который унаследовал трейт, в отличие от обычного наследования:

trait MyTrait{   
    protected function accessVar()   {     
       return $this->var;   
    } 
} 
class TraitUser{   
    use MyTrait;   
    private $var = 'var';   
    public function getVar()   {     
         return $this->accessVar();   
    } 
} 

$t = new TraitUser(); 
echo $t->getVar(); // -> 'var'  

четверг, 19 декабря 2013 г.

Разница между $this и self в PHP. Подробная версия.


У каждого обычно возникает вопрос, что такое $this, что такое self, для чего они используются и в чем разница между ними?
ПРАВИЛА КОТОРЫЕ ВЫ ДОЛЖНЫ ЗАПОМНИТЬ:

  1. Статические функции должны использовать только статические переменные.
  2. self ТОЛЬКО для статических функций, свойств. Но также можно вызвать нестатический метод, КАК СТАТИЧЕСКИЙ через self. Но лучше так не делать, а то папа побьет.
  3. this ТОЛЬКО для нестатических.
  4. this требует, чтобы класс был проинстанцирован, self не требует.

$this - это ССЫЛКА на ТЕКУЩИЙ объект и она нужна, чтобы обратиться к переменной в КОНТЕКСТЕ класса. К примеру:

class human {
     public $name;
     public function klassFunc() {};
     function getName() {
            echo $name; // неправильно, обратиться не к переменной public name
            echo $this->name; // правильно
            
            //вызов метода класса
            $this->klassFunc();
     }
}

Обычна нужна, чтобы инициализировать поля в конструкторе, ну и не только:

class human {
     public $name;   
     public function __construct($name){
          $this->name = $name;
          $name = $name; //будет ошибка
     }
}

$self используется в том, же самом ключе, но уже для СТАТИЧЕСКИХ свойств:

class human {
     static $name = "ololo";
     
     public function klassFunc() {};
     function getName() {
            echo self::$name; //обращение к name
            echo $this->name; //null или ошибка. НЕЛЬЗЯ
     }
}

Проверочная программа которая показывает главную разницу между self и $this:

class Klass {
const       
STAT 'S' // константы всегда статичныstatic     $stat 'Static' ;
public     
$publ 'Public' ;
private    
$priv 'Private' ;
protected  
$prot 'Protected' ;

function 
__construct( ){  }

public function 
show( ){
    print 
'<br> self::STAT: '.self::STAT// ссылается на константу
    
print '<br> self::$stat: '.self::$stat// статическая переменная.
    
print '<br>$this->stat: '.$this->stat // Ошибки нет, но выведет пустую строку. ПРЕДУПРЕЖДЕНИЕ.
    
print '<br>$this->publ: '.$this->publ // выведет как надо
    
print '<br>' ;
}
}
$me = new Klass() ;$me->show() ;

Результат:
self::STAT: S
self::$stat: Static
Strict Standards: Accessing static property Klass::$stat as non static in htdocs\test\testReference.php on line ..
Notice: Undefined property: Klass::$stat in C:\xampp\htdocs\test\testReference.php on line 50
$this->stat:
$this->publ: Public
Видно, что php умный и кидает предупреждения глупым программистам. Не делайте так.

Второе главное отличие состоит в том, что

self не использует таблицу виртуальных методов, то есть:
(взято с StackOverflow)

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();
Выведет:

Hello, I'm Ludwig the geek
Goodbye from Ludwig the person

Пояснение:
Метод sayHello использует this, поэтому виртуальная таблица вызовет Geek::getTitle()
Метод sayGoodbye использует self, поэтому виртуальная таблица будет не задействована и будет вызван parent::getTitle()

Решение:
Используем вместо self, static keyword:
public function sayGoodbye() {
      echo "Goodbye from ".static::getTitle();

Всем, спасибо, за внимание :)

среда, 14 августа 2013 г.

Интеграция библиотеки GObject/Glib в Code::Blocks


GObject - библиотека, которая является надстройкой над С, добавляющая в этот язык всю мощь Объектно ориентированного программирования.
Выглядит, конечно, как велосипед, везде макросы, очень странные требования, создание нескольких структур под разные цели (Private структура, Public структура итд), к тому же я не понимаю в чем смысл использовать ее, когда есть великий и могучий С++, но, если выбора нету, то придется использовать.
Причем GObject очень часто используется в GNOME. Напомню, что GObject является частью GTK+ (GIMP Toolkit). Для справки: На основе GTK+ написано окружение GNOME, XFCE, LXDE, KDE.
Этапы интеграции:
1) Установка Code::Blocks
2) Установка GObject (zypper install gcc gcc-c++ glib2-devel)
3) Создаем любой проект, где выбираем язык С.
4) Найдем где используется наша GObject библиотека:
     pkg-config --cflags --libs gobject-2.0
Получили результат (мой случай, в вашем может быть другой путь):
  -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -lgobject-2.0 -lglib-2.0
5) Идем в Project->Build Options->Compiler Settings->Other Options
6) Копируем (-I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include) в текстовое поле
7) Идем в Project->Build Options->Linker Settings->Other Linker Options
8) Копируем (-lgobject-2.0 -lglib-2.0) в текстовое поле
9) Строим проект
10) :EEE Все работает
Если есть вопросы, пишите, спасибо за внимание :3

суббота, 15 июня 2013 г.

Конвертер Hex String в Brush (Color) в Windows 8 (C#)

В приложениях Windows 8 для хранения цветов используется модель - RGBA (Red, Green, Blue, Alpha). Эта модель (цветовое пространство) известна всем со школы. 
В C# байты сначала идут - Alpha - Red - Green - Blue. Для каждого значения по 2 байта. 
Пример #FF000000 - Черный цвет, #FFFF0000 - Красный цвет.
Для тех, кто не знает, что такое Alpha - оно отвечает за прозрачность картинки, то есть, если у вас например RGBA = #FF000000 , здесь Alpha = 255, то есть картинка полностью непрозрачна, если Alpha = 0, то картинка полностью прозрачна.
Итак мне понадобилось сделать для моего приложения Windows Store простенький конвертер из Hex Строкового значения в объект типа SolidColorBrush. Преобразует строки типа - #FFFFFFFF. Проверок на длину строки нету.

public static class HexToColorConverter
    {
        public static SolidColorBrush GetColorFromHex(string hexColor)
        {
            hexColor = hexColor.Replace("#", ""); //удаляем решетку
            byte a = byte.Parse(hexColor.Substring(0, 2), System.Globalization.NumberStyles.HexNumber); //получаем alpha
            byte r = byte.Parse(hexColor.Substring(2, 2), System.Globalization.NumberStyles.HexNumber); //получаем красный
            byte g = byte.Parse(hexColor.Substring(4, 2), System.Globalization.NumberStyles.HexNumber); //получаем зеленый
            byte b = byte.Parse(hexColor.Substring(6, 2), System.Globalization.NumberStyles.HexNumber); //получаем синий
            return new SolidColorBrush(Color.FromArgb(a, r, g, b));
        }
    }

пятница, 14 июня 2013 г.

Хранение пароля и логина в приложении Windows 8 (C#)


Для хранения логинов и паролей в Windows 8 приложениях, Microsoft представила новый API, называемый PasswordVault (Хранилище паролей). При добавлении в это хранилище, происходит автоматическое шифрование данных, что очень удобно, если вы не хотите изобретать велосипед. Это только основы, для всех методов ссылка на MSDN
Для удобного взаимодействия с PasswordVault, я сделал 3 простых метода:
  • Метод добавления данных (SaveCredential)
  • Получения данных (GetCredential)
  • Удаления данных (RemoveCredential)
Особенности:

  • Помним, что для использования PasswordVault, требуется подключение библиотеки Windows.Security.Credentials
  • Для получения пароля или удаления данных, нужно знать логин
  • Если не найдены данные, то выкидывается исключение, к-ое надо обработать
  • Посмотреть добавленные данные можно в Control Panel -> User Accounts .. -> Credential Manager


В Windows каждому приложению отведен ресурс, который имеет имя. В нашем случае, я назвал его MyAppCredential. Это имя мы используем во всех методах при обращении к хранилищу.

private const string RESOURCE_NAME = "MyAppCredential"; //для добавления нужно название нашего ресурса
 
private void SaveCredential(string userName, string password)
{
    var vault = new PasswordVault(); //инициализируем хранилище
    var credential = new PasswordCredential(RESOURCE_NAME, userName, password);
    //добавляем данные, с помощью метода Add
    vault.Add(credential);
}
 
private void GetCredential()
{
    string userName; 
    string password;
 
    var vault = new PasswordVault();
    try
    {
        var credential = vault.FindAllByResource(RESOURCE_NAME).FirstOrDefault();
        if (credential != null)
        {
            // Получаем пароль и логин
            userName = credential.UserName;
            //ДЛЯ ПОЛУЧЕНИЯ ПАРОЛЯ НУЖНО ЗНАТЬ ЛОГИН
            password = vault.Retrieve(RESOURCE_NAME, userName).Password;
        }
    }
    catch (Exception)
    {
        // Если ничего не найдено, то обработать ошибку
    }
}
 
private void RemoveCredential(string userName)
{
    var vault = new PasswordVault();
    try
    {
        // Удаляем данные
        //ДЛЯ УДАЛЕНИЯ ДАННЫХ НУЖНО ЗНАТЬ ЛОГИН
vault.Remove(vault.Retrieve(RESOURCE_NAME, userName)); } catch (Exception) { // Если ничего не найдено, то обработать ошибку } }

воскресенье, 10 марта 2013 г.

Шаблон проектирования Команда (Command) + Реализация на C#

Существуют ситуации, когда у нас есть просто данные, над которыми нужно провести одну лишь единственную операцию, например, у нас есть кино на DVD диске и нам нужно всего лишь либо, запустить фильм, либо остановить, либо нажать на паузу и так далее. Также нам может понадобится такое действие, которое может отменить предыдущее (например операция undo в блокноте). Я могу написать функции (или методы), которые будут исполнять нашу команду и обрабатывать ее, но у нас будет очень много похожего кода, так как у нас не будет базового класса, который будет иметь поля схожие для всех команд. К тому же код будет очень не гибким. Фактически это КЛАСС, который инкапсулирует один единственный метод execute(). Это позволяет нам хранить команды в каких то контейнерах, обрабатывать их с помощью наших обработчиков.
(Пример стыбзен с википедии). Мы проектируем калькулятор со стандартными операциями сложения, деления, умножения, вычитания
Все строится сначала на классе Command:

abstract class Command
  {
    public abstract void Execute(); //метод выполнения команды
    public abstract void UnExecute(); //метод отмены
  }
Теперь делаем производные классы от команды. Причем этот класс должен хранить получателя(Calculator), класс, который принимает команды и обрабатывает их.

class CalculatorCommand : Command
  {
 char @operator; //оператор
 int operand;
 Calculator calculator; //ОБЪЕКТ ПОЛУЧАЮЩИЙ КОМАНДЫ (Receiver)
 
    // Constructor
 public CalculatorCommand(Calculator calculator,
    char @operator, int operand)
    {
      this.calculator = calculator;
      this.@operator = @operator;
      this.operand = operand;
    }
 
    public char Operator
    {
      set{ @operator = value; }
    }
 
    public int Operand
    {
      set{ operand = value; }
    }
 //здесь мы просто вызываем метод нашего получателя, на вход которого мы отправляем оператор и операнд
    public override void Execute() 
    {
      calculator.Operation(@operator, operand);
    }
 
    public override void UnExecute()
    {
      calculator.Operation(Undo(@operator), operand);
    }
 
    // Private helper function : приватные вспомогательные функции
    private char Undo(char @operator)
    {
      char undo;
      switch(@operator)
      {
        case '+': undo = '-'; break;
        case '-': undo = '+'; break;
        case '*': undo = '/'; break;
        case '/': undo = '*'; break;
        default : undo = ' '; break;
      }
      return undo;
    }
  }
Теперь нужен класс который будет получать команды и их обрабатывать.

// "Receiver" : получатель
 
  class Calculator
  {
    private int curr = 0;
 
    public void Operation(char @operator, int operand)
    {
      switch(@operator)
      {
        case '+': curr += operand; break;
        case '-': curr -= operand; break;
        case '*': curr *= operand; break;
        case '/': curr /= operand; break;
      }
      Console.WriteLine(
        "Current value = {0,3} (following {1} {2})",
        curr, @operator, operand);
    }
  }
Теперь нужен класс, который будет отдавать команды на обработку калькулятору..

class User
  {
    // Initializers
    private Calculator _calculator = new Calculator();
    private List _commands = new List();
 
    private int _current = 0;
 
    public void Redo(int levels)
    {
      Console.WriteLine("\n---- Redo {0} levels ", levels);
 
      // Делаем возврат операций
      for (int i = 0; i < levels; i++)
        if (_current < _commands.Count - 1)
          _commands[_current++].Execute();
    }
 
    public void Undo(int levels)
    {
      Console.WriteLine("\n---- Undo {0} levels ", levels);
 
      // Делаем отмену операций
      for (int i = 0; i < levels; i++)
        if (_current > 0)
          _commands[--_current].UnExecute();
    }
 
    public void Compute(char @operator, int operand)
    {
 
      // Создаем команду операции и выполняем её
      Command command = new CalculatorCommand(
        _calculator, @operator, operand);
      command.Execute();
 
      // Добавляем операцию к списку отмены
      _commands.Add(command);
      _current++;
    }
  }
Ну и пример работы с нашим калькулятором

class MainApp
  {
    static void Main()
    {
      // Создаем пользователя.
      User user = new User();
 
      // Пусть он что-нибудь сделает.
      user.Compute('+', 100);
      user.Compute('-', 50);
      user.Compute('*', 10);
      user.Compute('/', 2);
 
      // Отменяем 4 команды
      user.Undo(4);
 
      // Вернём 3 отменённые команды.
      user.Redo(3);
 
      // Ждем ввода пользователя и завершаемся.
      Console.Read();
    }
  }
Итак, теперь обобщим все, что мы здесь написали, вот схемка шаблона:
Ну, кто не силен в английском, могу объяснить, сначала наш вызывающий (по английски Invoker) (в нашем случае User), вызывает команду (причем команда передается в виде объекта) и посылает ее получателю (Calculator), где команда успешно обрабатывается калькулятором.
Благодаря такому шаблону, мы можем без труда можем добавить свои команды, которые с помощью метода execute() будут также выполнятся. Всего лишь надо унаследовать все от Command.