C# Паттерны Проектирования - Пример
Primary tabs
Forums:
Подробнее о теории паттернов здесь
Итак - пусть у нас есть программа:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace CheckersPatternGame
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
мы будем играть в шашки
Вот код адаптера - адоптируем данные в команду:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace CheckersPatternGame
{
public class Adapter : myCheckersCommand1
{
public TextBox tx1, ty1, tx2, ty2; // текст в этих вот друзьях мы будем адаптировать в команду.
public Adapter(Facade Adrr, TextBox tx12,TextBox ty12,TextBox tx22,TextBox ty22)
{
this.Addressee = Adrr;
tx1 = tx12;
ty1 = ty12;
tx2 = tx22;
ty2 = ty22;
this.Update();
}
public void Update() // проверка и запоминание координат.
{ int a;
if (Int32.TryParse(tx1.Text, out a))
{ if ((a>=1)&&(a<=8))
this.x1 = a;
}
else
throw new UnexpectedTypeExeption("В качестве координат указывайте целые числа от одного до восьми!");
if (Int32.TryParse(ty1.Text, out a))
{
if ((a >= 1) && (a <= 8))
this.y1 = a;
}
else
throw new UnexpectedTypeExeption("В качестве координат указывайте целые числа от одного до восьми!");
if (Int32.TryParse(tx2.Text, out a))
{
if ((a >= 1) && (a <= 8))
this.x2 = a;
}
else
throw new UnexpectedTypeExeption("В качестве координат указывайте целые числа от одного до восьми!");
if (Int32.TryParse(ty2.Text, out a))
{
if ((a >= 1) && (a <= 8))
this.y2 = a;
}
else
throw new UnexpectedTypeExeption("В качестве координат указывайте целые числа от одного до восьми!");
}
}
//---------далее немного исклбчений-------------------
public class UnexpectedTypeExeption : ChackersExeption // базовый класс исключений для нашей коллекции
{
private const string SelfMessage = " Unexpected Type -> ";
public UnexpectedTypeExeption() : base(String.Format("{0}", SelfMessage)) { }
public UnexpectedTypeExeption(string s) : base(String.Format("{0}{1}", SelfMessage, s)) { } // формируем Message-свойство -сообщение.
}
}
а вот это фасад - он будет хранить состояние игрового поля:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CheckersPatternGame
{
public abstract class Facade
{
public abstract void Make_a_Move(int x1,int x2,int y1,int y2); // даже для шахмат такой вот обобщённый формат хода подойдёт.
}
public class ChakersFacade1 : Facade
{ // ?????? почему в конструкторе нельзя void в данном случае ?
public Shashka[] FigMass; // Фасад будет хранить два массива фигур - одщий для обоих игров, те фигуру, что будут иметь индекс больше 12-ого - это "чёрные" Наблюдатель нарисует их на форме сверху.
public ChakersFacade1() // в этом конструкторе мы займёмся "подготовкой" игры - "расставим " фигуры , определим их цвет - это "программа минимум"
{
int x = 1, y = 1; // начальные координаты для расстановки.
bool b=false; // проверка чётности номера строки клеток (не помню функцию , позволяющую определить отстаток от деления в си шарп) перва я строка - чётная.
this.FigMass= new Shashka[24]; // выделяем память для массива фигур.
for (int i=0;i<=23;i++) // инициаллизируем каждую фигуру.
{ // в цикле мы определяем цвет фигуры и её координаты ,причём перва яполучает координаты [1;1]
FigMass[i] = new ProstoShashka();
FigMass[i].X = x; // запоминаем координаты.
FigMass[i].Y = y;
if (i <= 11) FigMass[i].isWhite = true; // то есть если это белая фигура. (чёрной фигура является по-умолчанию)
// далее ряд опереций, связанных с вычислением очередной координаты
if ((x == 7) && (y == 3)) // выполнение этого условия будет означать, что все белые уже расставлены.
{
y = 6; x = 2; b = true; // определяем координаты первой чёрной фигуры.
}
else // если все белые ещё не расставлены или раставлены более одной итерации цикла назад.
{
if ((x != 7) && (x != 8)) x = x + 2; // расставляем через клетку потому и увеличиваем икс на два.
else
{
y = y + 1; // переходим на следующую строка , если заполнена предыдущая.
if (b == false) b = true; else b = false; // меняем чётность/нечётность.
if (b == false) x = 1; else x = 2; // определяем начальную координату клетки на очередной сторе в зависимости от чётности/нечётности последней.
}
}
}
this.UpdateObservers();// предлагаем наблюдателям обновиться - показать все шашки на исходных позициях.
// на этом расстановка и покраска фигур завершается. теперь пишем обработчик хода.
}
Shashka ActiveFig; // фигура, которой собираются ходить, та, которая выбрана для хода.
public override void Make_a_Move(int x1, int y1, int x2, int y2) // обработчик хода.
{
Shashka[] figuresOnThePathMass = null; // фигуры, которые находятся на траектории хода.
Cell[] curcellmass; // координаты траектории передаваемого хода -получаем этот массив от фигуры.
Cell[] cellmassWithoutActiveFig = null; // массив координат без тех , на которых фигура итак размещена - и без последней, которая должна быть свободной для хода.
this.ActiveFig = this.GetSpecFigure(x1, y1);
if (ActiveFig != null)
{
curcellmass = ActiveFig.CanMoveTo(x2,y2);
if (curcellmass != null) // если фигура теоретически может так походить ,то начинаем изучать ситуацию на поле
{ /* далее мы описываем фасад исходя из тех принципов, что любая шашка - как дамка так и не дамка должна за один ход либо не переступить
* ни одной шашки либо переступить только одну - при элементарном ударе, при этом клетка с конечным адресом должна быть свободой.
* вот и вся логика*/
if (IsCellFree(x2, y2)) // проверяем доступность конечной координаты. - то , что клетка свободна.
{
if (curcellmass.Length == 1) throw new NoPathExeption("шашка уже итак стоит на этой клетке.");
else if (curcellmass.Length == 2) // если это просто ход на соседнюю по-диагонали , тогда "ходим"
{
ActiveFig.X = x2;
ActiveFig.Y = y2;
}
else
{
// далее выделяем из массива координат те , которые не являются начальными и конечными.
cellmassWithoutActiveFig = new Cell[curcellmass.Length - 2]; //
int i=0;
foreach (Cell c in curcellmass) // переписываем интересующие нас координаты в новый массив.
{
cellmassWithoutActiveFig[i] = curcellmass[i + 1];
}
// for (int i = 1; i <= curcellmass.Length - 1; i++)
// {
// cellmassWithoutActiveFig[i - 1] = curcellmass[i]; // переписываем интересующие нас координаты в новый массив.
// }
figuresOnThePathMass = GetFigMassOnThePath(cellmassWithoutActiveFig); // получаем фигуры на интересующем нас отрезке траектории.
if (figuresOnThePathMass != null)
{
if ((figuresOnThePathMass.Length == 1) && (this.ActiveFig.isWhite != figuresOnThePathMass[0].isWhite)) // если на пути только одна шашка противника.
{
figuresOnThePathMass[0].IsKilled = true; // шашка противника побита.
ActiveFig.X = x2;
ActiveFig.Y = y2;
}
else if ((figuresOnThePathMass.Length == 1) && (this.ActiveFig.isWhite == figuresOnThePathMass[0].isWhite))
throw new CantBeatFriendlyUnitExeption(" своих не бьют!");
else if (figuresOnThePathMass.Length > 1)
throw new CantMakeSoMoreSacrificesExeption("Не всё сразу. Бейте по-одной.");
}
}
}
}
}
this.UpdateObservers();// предлагаем наблюдателям обновиться.
} // здесь обработка хода заканчивается - можно приступать к системе визуализации - Наблюдателю и Адаптеру, если говорить о паттернах.
public bool IsCellFree(int x, int y) // вспомогательная функция, проверяет - является ли указнная ячейка свободной.
{
bool b = true;// ответ функции.
foreach (Shashka curfigure in FigMass )
{
if ((curfigure.X == x) && (curfigure.Y == y)) b = false; // вот и вся проверка.
}
return b;
}
public Shashka GetSpecFigure(int x, int y) // вспомогательная функция возвращает фигуру , если такова я имеется на пересечении указанных координат.
{
Shashka shash = null;
foreach (Shashka curfigure in this.FigMass)
{
if ((curfigure.X == x) && (curfigure.Y == y)) { shash = curfigure; break; } // вот и вся проверка.
}
return shash;
}
public Shashka[] GetFigMassOnThePath(Cell[] cellmass) // возвращает массив фигур, размещённых намножестве переданных клеток.
{
Shashka[] rez= new Shashka[0] ; // function result
foreach (Shashka shash in this.FigMass) // перебираем фигуры
{
foreach (Cell cell in cellmass) // перебираем клетки траектории.
{
if ((shash.X == cell.x) && (shash.Y == cell.y))
{
Array.Resize(ref rez, rez.Length + 1);
rez[rez.Length - 1] = shash;
}
}
}
return rez;
}
private Observer[] Observers = new Observer[0];
public void UpdateObservers()
{
foreach (Observer v in Observers)
{
v.UpdateView();
}
}
public void AddObserver(Observer nv )
{
Array.Resize(ref this.Observers, this.Observers.Length + 1);
this.Observers[this.Observers.Length-1] = nv; // добавляем ещё одного наблюдателя, реализующего интерфейс, опять же, наблюдателя.
}
}
//--------далее набор всевозможных исключительных ситуаций - чтобы играть было веселее.)))--------------
public class ChackersExeption : ApplicationException // базовый класс исключений для нашей коллекции
{
private const string ChackersEceptionMessage = "(!) Problem with the checkers game-> ";
public ChackersExeption() : base(String.Format("{0}", ChackersEceptionMessage)) { }
public ChackersExeption(string s) : base(String.Format("{0}{1}", ChackersEceptionMessage, s)) { } // формируем Message-свойство -сообщение.
}
public class NoPathExeption :ChackersExeption // базовый класс исключений для нашей коллекции
{
private const string SelfMessage = " path doesn't exist -> ";
public NoPathExeption() : base(String.Format("{0}", SelfMessage)) { }
public NoPathExeption(string s) : base(String.Format("{0}{1}", SelfMessage, s)) { } // формируем Message-свойство -сообщение.
}
public class CantMoveExeption : ChackersExeption // базовый класс исключений для нашей коллекции
{
private const string SelfMessage = " can't move -> ";
public CantMoveExeption() : base(String.Format("{0}", SelfMessage)) { }
public CantMoveExeption(string s) : base(String.Format("{0}{1}", SelfMessage, s)) { } // формируем Message-свойство -сообщение.
}
public class CantBeatFriendlyUnitExeption : ChackersExeption // базовый класс исключений для нашей коллекции
{
private const string SelfMessage = "It's friendly shachka -you can't beat it-> ";
public CantBeatFriendlyUnitExeption() : base(String.Format("{0}", SelfMessage)) { }
public CantBeatFriendlyUnitExeption(string s) : base(String.Format("{0}{1}", SelfMessage, s)) { } // формируем Message-свойство -сообщение.
}
public class CantMakeSoMoreSacrificesExeption : ChackersExeption // базовый класс исключений для нашей коллекции
{
private const string SelfMessage = " can't beat so more units at one motion -> ";
public CantMakeSoMoreSacrificesExeption() : base(String.Format("{0}", SelfMessage)) { }
public CantMakeSoMoreSacrificesExeption(string s) : base(String.Format("{0}{1}", SelfMessage, s)) { } // формируем Message-свойство -сообщение.
}
}
а вот код для фигуры - он сделает её независимой от игрового мира:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/*шашки паттерны ооп*/
namespace CheckersPatternGame
// лучше всег начать с описания класса Фигура.
// начинаем с фигуры -главного юнита нашей игры .
{ /* 1)Волевым решением создатель этого далеко не самого совершенного кода постоновляет -
мы будем узнавать возможность сделать ход у фигуры ,но так как фигура ничего не должна знать о фасаде по-идее (это сделает её универсальной)
то фигура будет просто отвечать типа "в общем случае со своей клетки я могу походить на предлагаемую клетку" или же "не могу",
* в свою очередь Фасад, который, как ,опять же - предполагает автор данного кода ,"знает" о фигурах , которыми он двигает, и может перемещать их, или
* же убирать с поля "побитые" - "спрашивает" у фигуры - может ли она чисто теоретически достигнуть указанной клетки,
* если может - он проводит ряд собственных проверок и действий, связанных с расположением наигровом уже других фигур
* и если проверки закачиваются успехом(всё соответствует правилам) игры фасад производит соответствующие ходу преобразования игрового поля.
* Вот, собственно, и всё задумка, отностильно взаимодействия фигуры и фасада -
* фасад спрашивает может ли фигура чисто теоретически
* (то есть , не учитывая, например того, что на данной клетке уже кто-то стоит) совершить элементарный ход (или
* элементарный удар) на эту позицию (например фасад шашек, который мы здесь реализуем
* спросит просто возможность однократного удара или хода - сам при этом проверив -есть ли кого бить в случае удара и не занята ли клекта которыю
* предполагается занять после хода/удара) то есть - ключевой момент частого решения проектирования здесь состоит именно в проверке
* элементарных хода и удара у фигуры - все остальные решения же будет принимать фасад - причём некая в определённым смысле, "частная" его версия,
* заточенная для работы именно с данным типом фигур в данной игре (шашки и дамки в шашках, различные фигуры в шахматах, лиса и четыре гуся а игре
* "Лиса и гуси")
* 2) В ходе дополнительных размышлений автор приходит к выводу о том, что фигура должна возврашать не только ответ о способности
* совершить ход но и МАССИВ КООРДИНАТ ПРИНАДЛЕЖАЩИХ ЕЁ ТРАЕКТОРИИ ДАННОГО ХОДА. это сделает фигуру полностью самостоятельной , а фасад
* в свою очередь уже будет отвечать только за взаимодействие фигур на поле.
*
*/
public abstract class Figure // это класс фигуры для "движка" игры, то есть Фасада. ????? - почему здесь нужен паблик перед классом - иначе появится Error 1 Inconsistent accessibility: base class 'CheckersPatternGame.Figure' is less accessible than class 'CheckersPatternGame.Shashka'
{
private int XFiled, YFiled; //целочисленные координаты фигуры на поле.
public int X //
{
get { return this.XFiled; }
set { this.XFiled = value; }
}
public int Y //
{
get { return this.YFiled; }
set { this.YFiled = value; }
}
public bool IsKilled = false; // при инициализации фигура жива.
public string Name; // наименование фигуры (это поле инициализировать в игре не обязательно.) - может пригодится например, при выводе ошибки
public abstract Cell[] CanMoveTo(int x2, int y2); // этот метод размышляет над тем - можно ли походить или нет - если может - возвращает "true", иначе "false"
}
//------------------------------
// далее -классы для реализации паттерна Состояния фигуры.
public abstract class Shashka : Figure // просто наследуемся от фигуры.
{
public bool isWhite = false; // добавим для шашек цвет - по-умолчанию=чёрный - хотя на самом деле - просто один из двух.
public Shashka(int x, int y) // создавать фигуру без начального размещения на поле вроде как бессмыслено - поэтому заводим вот такой вот конструктор.
{
this.X = x;
this.Y = y;
}
public Shashka() // явный конструктор по умолчанию, чтобы наследоваться.
{}
}
public class ProstoShashka : Shashka
{
public override Cell[] CanMoveTo(int x2, int y2)
{
Cell[] rez=null; // ответ фигуры на вопрос о способности совершить ход.
if (this.isWhite == true)
{
if ((((this.X - x2) == 1) || ((this.X - x2) == -1)) && ((this.Y - y2) == -1)) // с помощью этого выражения фигура убеждается что ей предлагают просто походить вперёд(при этом вправо или влево.)
rez = GetPath(this.X, this.Y, x2, y2); // получаем траекторию
else if ((((this.X - x2) == 2) || ((this.X - x2) == -2)) && (((this.Y - y2) == -2) || ((this.Y - y2) == 2))) // так по поей мысли определяет элементарный удар в четырёх направлениях по диагонали ,причём если бы я знал функцию модуля , то написал бы красивее, но функции модуляы я не знаю, а интернет не работает.
rez = GetPath(this.X, this.Y, x2, y2); // получаем траекторию
return rez;
}
else
{
if ((((this.X - x2) == 1) || ((this.X - x2) == -1)) && ((this.Y - y2) == 1)) // с помощью этого выражения фигура убеждается что ей предлагают просто походить вперёд(при этом вправо или влево.)
rez = GetPath(this.X, this.Y, x2, y2); // получаем траекторию
else if ((((this.X - x2) == 2) || ((this.X - x2) == -2)) && (((this.Y - y2) == -2) || ((this.Y - y2) == 2))) // так по поей мысли определяет элементарный удар в четырёх направлениях по диагонали ,причём если бы я знал функцию модуля , то написал бы красивее, но функции модуляы я не знаю, а интернет не работает.
rez = GetPath(this.X, this.Y, x2, y2); // получаем траекторию
return rez;
}
}
static Cell[] GetPath(int x1, int y1, int x2, int y2) // эту функцию можно будет использовать и для дамки.
{
// bool b = false; //используется при определении траектории.
Cell[] rez = new Cell[0];
int xz, yz,x,y;
x = x1; y = y1;
Array.Resize(ref rez, 1);
rez[0] = new Cell(x,y);
// rez[0].x = x; rez[0].y = y; // траектория как минимум будет выражденной -только исходная клетка.
if ((x1 != x2) || (y1 != y2))
{
if (x1 == x2) xz = 1;
else // определяем - возрастает или убывает x;
xz = Math.Abs(x2 - x1) / (x2 - x1);
if (y1 == y2) yz = 1;
else // определяем - возрастает или убывает y;
yz = Math.Abs(y2 - y1) / (y2 - y1);
/* возврат траектории может потребоваться тодько в случае , если фигура "счиатает" ,
* что она можнет так походить - сответственно, в шашках достаточно просто "провести прямую" из начала в конец хода - это
и будет траетория*/
while ((x != x2) || (y != y2))
{
x = x + xz; // движемся по прямой (а может и нет если второе слогаемое равно нулю.)
y = y + yz; // движемся но прямой (а может и нет если второе слогаемое равно нулю.)
Array.Resize(ref rez, rez.Length + 1); // выделяем память для ещё одного элемента массива.
rez[rez.Length - 1] = new Cell(x, y); // запоминаем координаты очередной клетки
// rez[rez.Length - 1].x = x; // запоминаем координату очередной клетки
// rez[rez.Length - 1].y = y; // запоминаем координату очередной клетки
} // на этом вычисление траектории закончено.
}
return rez; // возвращаем массив значений.
}
// на этом описание "просто шашки" (не "дамки") можно прекратить и заняться фасадом, который , собственно, и будет руководить игрой.
}
//--------------------------------------------------далее -
//вспомогательный класс, описывающий клетку - содержит только две координаты -необходим для передачи траектории хода в виде массива клеток.
public class Cell
{
public Cell(int x, int y)
{
this.x = x;
this.y = y;
}
public int x;
public int y;
}
}
А вот это Наблюдатель - он будет рисовать для нас игровое поле - отображая для пользователя внутренне состоянием игрового мира
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace CheckersPatternGame
{
public abstract class Observer // шаблон для всех наблюдателей
{
public abstract void UpdateView(); // метод который призывает наблюдателя обновиться в соответствии с возможным изменением наблюдаемого.
}
public class GameFiledView1 : Observer // наш конкретный наблюдатель.
{
public GameFiledView1(Graphics bm, ChakersFacade1 cfd) // наш наблюдатель теряет смысл существования без места, где он может рисовать и натуры, образ которой можно запечатлеть на плоскости.
{
this.BitMap = bm;
this.UpdateSourse = cfd;
// this.PaintArgs = e;
}
Graphics BitMap;// то, на чём мы будем рисовать.
ChakersFacade1 UpdateSourse; // то, с чем мы будем согласовывать графическое представление (рисование).
// PaintEventArgs PaintArgs;
public override void UpdateView()
{
Brush brush1 = new SolidBrush(Color.Chocolate);
Brush brush2 = new SolidBrush(Color.White);
Brush brush5 = new SolidBrush(Color.BurlyWood);
Brush brush3 = new SolidBrush(Color.Black);
Brush brush4 = new SolidBrush(Color.DarkOliveGreen);
Pen blackPen = new Pen(Color.BurlyWood, 3);
Brush brush7 = new SolidBrush(Color.DarkSlateGray);
// залём фон
BitMap.FillRectangle(brush4, 0, 0, 1000, 1000);
BitMap.FillRectangle(brush7, 45, 45, 325, 325);
// рисуем поле.
int d = 40; // параметр для рисования.
int с = 25; // параметр для рисования.
int h = 8; // параметр для рисования.
int x = 1, y = 1; // -координаты.
bool b = false;
for (int i = 1; i <= 64; i++)
{
if (b == true) BitMap.FillRectangle(brush2, x * d, y * d, d, d);
else BitMap.FillRectangle(brush3, x * d, y * d, d, d);
if (x == 8)
{
y = y + 1;
x = 1;
}
else
{
x = x + 1;
if (b == true) b = false; else b = true;
}
}
foreach (Shashka sha in this.UpdateSourse.FigMass)
{
// Rectangle rect = new Rectangle(sha.X * 30, sha.Y * 20, sha.X * 20 + 100, sha.Y * 20 + 100);
//Rectangle rect = new Rectangle(50, 50, 158, 158);
// PaintArgs.Graphics.DrawEllipse(blackPen, sha.X * 20, sha.Y * 20, 20,20);
if (sha.IsKilled == false)
{
if (sha.isWhite == false)
BitMap.FillEllipse(brush1, sha.X * d + h, sha.Y * d + h, с, с);
else
BitMap.FillEllipse(brush5, sha.X * d + h, sha.Y * d + h, с, с);
}
}
}
}
}
вот в этом файле вы используем паттерн Команда - а также создадим класс игрока (кстати число игроков можно было бы ограничить паттерном Одиночка - но мы это тут делать не станем):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CheckersPatternGame // здесь мы соберём набор классов, используемых в патерне "Команда" и те. что относятся и интерфейсу Player.
{ // далее паттерн КОМАНДА
public abstract class Command // общий интерфейс для всех команд приложения.
{
public abstract void Execute();
}
public class myCheckersCommand1 : Command // команда выполнения хода.
{
private Facade AddresseeFiled; // доступ только через свойство + адресат , то есть собственно тот класс , которому и будет передаваться команда - это просто наследник от фасада.
private int x1Filed, y1Filed, x2Filed, y2Filed;
public Facade Addressee // используем это свойство для получения и смены адресата.
{
get { return this.AddresseeFiled; }
set { this.AddresseeFiled = value; }
}
public int x1 // координата начального положения.
{
get { return this.x1Filed; }
set { this.x1Filed = value; }
}
public int y1 // координата начального положения.
{
get { return this.y1Filed; }
set { this.y1Filed = value; }
}
public int x2 // предполагаемая координата после выполнения хода.
{
get { return this.x2Filed; }
set { this.x2Filed = value; }
}
public int y2 //предполагаемая координата после выполнения хода.
{
get { return this.y2Filed; }
set { this.y2Filed = value; }
}
public myCheckersCommand1(int x1,int x2,int y1,int y2) // конструктор для создания команды выполнения хода.
{ // запоминаем координаты хода.
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public myCheckersCommand1() // явный конструктор по-умолчанию.
{ }
public override void Execute() // собственно метод посылает команду тому, кто её будет исполнять.
{
this.Addressee.Make_a_Move(this.x1,this.y1,this.x2,this.y2); // приказываем фасаду выполнить ход - то есть изменить данные о расположении фигур на поле.
}
}
//----------------------------------------------------------
// Далее определение объекта типа PLAYER
public abstract class Player // итак, некий "интерфейс" для класса игрок, который и будет посылать команды игре, а конктренто - Фасаду.
{
private Command MakeAMoveCurCommandFiled; // доступ только через свойство + адресат , то есть собственно тот класс , которому и будет передаваться команда - это просто наследник от фасада.
public abstract void Make_a_Move(); // наш игрок пока что может сделать одно единственное действие - отменить ход.
public Command MakeAMoveCurCommand // используем это свойство для получения и смены адресата.
{
get { return this.MakeAMoveCurCommandFiled; }
set { this.MakeAMoveCurCommandFiled = value; }
}
}
public class myCheckersPlayer1 : Player
{
public myCheckersPlayer1(Command cmd)
{
this.MakeAMoveCurCommand = cmd;
}
public override void Make_a_Move()
{
this.MakeAMoveCurCommand.Execute();
}
}
}
- Log in to post comments
- 8894 reads