Справочник от Автор24
Поделись лекцией за скидку на Автор24

Введение в паттерны проектирования

  • 👀 468 просмотров
  • 📌 412 загрузок
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Введение в паттерны проектирования» pdf
Введение в паттерны проектирования 1) Список паттернов Началось с книги: Приёмы объектно-ориентированного проектирования. Паттерны проектирования» (англ. Design Patterns: Elements of Reusable Object-Oriented Software) — книга 1994 года, описывающая шаблоны проектирования программного обеспечения. Авторами книги, которых прозвали «Бандой четырёх», являются Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес. Через 20 лет интерес к ним резко усилился, как примерно произошло и с Python. Много лет после создания никому он был не нужен, а теперь, стандарт для искусственного интеллекта и смежных областей. Описанные в книге 23 паттерна (шаблона проектирования)    Порождающие шаблоны проектирования o Abstract Factory — Абстрактная фабрика o Builder — Строитель o Factory Method — Фабричный метод o Prototype — Прототип o Singleton — Одиночка Структурные шаблоны проектирования o Adapter — Адаптер o Bridge — Мост o Composite — Компоновщик o Decorator — Декоратор o Facade — Фасад o Flyweight — Приспособленец o Proxy — Заместитель Поведенческие шаблоны проектирования o Chain of responsibility — Цепочка обязанностей o Command — Команда o Interpreter — Интерпретатор o Iterator — Итератор o Mediator — Посредник o Memento — Хранитель o Observer — Наблюдатель o State — Состояние o Strategy — Стратегия o Template method — Шаблонный метод o Visitor — Посетитель Паттерн проектирования — это способ построения исходного кода программы для решения часто возникающих в повседневном программировании проблем. Это уже готовые решения, для типичной задачи. При этом паттерн просто алгоритм действий. 2) Примеры классов и объектов на C# на конкретном примере Пусть в проекте имеются геометрические фигуры квадратов и равносторонних треугольников. Для каждой фигуры требуется вычислять расстояние до начала координат от ее центра, площадь и периметр фигуры. Таким образом, у всех трех типов фигур имеются три вещественные переменные (поля), X,Y,L координаты центра и длина стороны и три функции (методы) D, S, P расстояние, площадь, периметр. Кроме этого, чтобы в main можно было задать переменные типа конкретной фигуры (объекты), проще всего определить специальный метод, имя которого совпадает с именем класса (конструктор). При этом доступ к полям будет возможен только из методов класса (модификатор private), а методы можно вызывать также вне класса, в main (модификатор public). Пример 1. Проект с геометрическими фигурами двух типов using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace Pattern2 { class Triange { private double X,Y,L; // координаты центра и сторона public Triange(double XX,double YY,double LL) // конструктор { X = XX; Y = YY; L = LL; // доступ к X, Y возможен из класса } public double D() // расстояние до начала координат { return Math.Sqrt(X * X + Y * Y); } public double S() // площадь фигуры треугольник { return L * L * Math.Sqrt(3.0) / 8; } public double P() // периметр фигуры треугольник { return 3 * L; } } class Square // класс квадрат { private double X, Y, L; // координаты центра и сторона public Square(double XX, double YY, double LL) // конструктор { X = XX; Y = YY; L = LL; } public double D() // расстояние до начала координат { return Math.Sqrt(X * X + Y * Y); } public double S() // площадь фигуры квадрат { return L * L; } public double P() // периметр фигуры квадрат { return 4 * L; } } class Program { static void Main(string[] args) { double d, s, p,x; Triange a = new Triange(4, 3, 6); // new вызывает конструктор треугольника d = a.D(); s = a.S(); p = a.P(); // x = a.X; к private полю X из main достуа нет Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Square b = new Square(5, 12, 5); // new вызывает конструктор квадрата d = b.D(); s = b.S(); p = b.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Console.ReadKey(); } } } Между классами Triangle и Square имеются одинаковые элементы, поля X, Y, L и метод D. Поэтому выгодно создать для них общий класс Figure с этими элементами, а классы Triangle и Square объявить как производные классы от Figure, который становится базовым для них. Производный класс содержит все, что есть в базовом плюс дополнительные элементы. В ООП это называется наследованием. При этом некоторые функции из базового класса могут быть переопределены (перегружены) . Поля и методы базового класса, которые были объявлены private, если при этом в производном классе они появляются как идентификаторы, то должны быть объявлены в базовом классе protected, иначе к ним будет доступ только из базового класса. Модификатор protected означает, что к элементу может быть доступ как в самом классе так и в любом производном от него на любом уровне иерархии. Конструктор производного класса с параметрами в заголовке должен в явном виде вызвать конструктор базового класса. Пример 2. Проект с геометрическими фигурами двух типов с общим базовым классом Figure для них. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace Pattern3 { class Figure { protected double X, Y, L; // возможен доступ из производных классов public Double D() { return Math.Sqrt(X * X + Y * Y); } public Figure(double XX, double YY, double LL) // конструктор базового класса { X = XX; Y = YY; L = LL; // доступ к X, Y возможен из класса } public double S() // площадь фигуры { return 0; } public double P() // периметр фигуры { return 0; } } class Triangle :Figure // производный класс от Figure { public Triangle(double XX, double YY, double LL):base(XX,YY,LL) // конструктор с явным вызовом конструктора базового { // здесь дополнительные задания проолей производного класса } public new double S() // площадь фигуры треугольник перегружен базовый метод { return L * L * Math.Sqrt(3.0) / 8; // L в базовом Figure protected значит можно использовать } public new double P() // периметр фигуры треугольник перегружен { return 3 * L; } } class Square:Figure // класс квадрат производный от Figure { public Square(double XX, double YY, double LL):base(XX,YY,LL) // конструктор с вызовом базового { // возможные дополнительные задания величин } public new double S() // площадь фигуры квадрат перегружен { return L * L; } public new double P() // периметр фигуры квадрат перегружен { return 4 * L; } } class Program { static void Main(string[] args) { double d, s, p; Triangle a = new Triangle(4, 3, 6); // new вызывает конструктор треугольника d = a.D(); s = a.S(); p = a.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Square b = new Square(5, 12, 5); // new вызывает конструктор квадрата d = b.D(); s = b.S(); p = b.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Figure c = new Triangle(4, 3, 6); // new вызывает конструктор базового класса Figure d = c.D(); s = c.S(); p = c.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Console.ReadKey(); } } } Несколько не логично выглядит задание нулю площади и периметру объектам Figure, площади и периметры треугольников и квадратов тоже могут быть равными нулю. В сложных классах легко запутаться, поэтому в ООП появились абстрактные классы с абстрактными функциями, которые пустые. В приложении нельзя создавать объекты абстрактных классов. Пример 3. Проект с геометрическими фигурами двух типов с абстрактным базовым классом Figure для них. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern4 { abstract class Figure // абстрактный класс { protected double X, Y, L; public Figure(double xx, double yy, double ll) { X = xx; Y = yy; L = ll; } public Double D() // обычная не абстрактная наследуемая функция { return Math.Sqrt(X * X + Y * Y); } public abstract double S(); public abstract double P(); // абстрактная функция // абстрактная функция } class Square : Figure // производный не абстрактный класс { public Square(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return L * L; } public override double P() // периметр фигуры квадрат перегружен { return 4 * L; } } class Triangle : Figure // производный не абстрактный класс { public Triangle(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return L * L * Math.Sqrt(3.0) / 8; } public override double P() // периметр фигуры треугольник перегружен { return 3 * L; } } class Program { static void Main(string[] args) { double d, s, p; Triangle a = new Triangle(4, 3, 6); // new вызывает конструктор треугольника d = a.D(); s = a.S(); p = a.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Square b = new Square(5, 12, 5); // new вызывает конструктор квадрата d = b.D(); s = b.S(); p = b.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Figure f = new Figure(1,2,4); // нельзя построить объект абстрактного класса Console.ReadKey(); } // } } Иногда удобно, чтобы класс наследовал методы от нескольких классов. В отличие от C++, в C# отсутствует множественное наследование, но его можно задать, если базовые классы содержат только абстрактные функции. Для них есть специальное ключевое слово interface. Интерфейс представляет собой аналог абстрактного класса, в котором есть только абстрактные методы. Класс реализует (implements) интерфейс, если он перегружает абстрактные методы интерфейса. Запишем пример с фигурами через интерфейсы. Добавим класс Ellipse, который имеет поля a, b - длины полуосей эллипса. Этот класс не является производным от Figure, а сам по себе. Для вычисления площади фигур и их периметров используются интерфейсы Space и Perimetr. В заголовке класса сначала указывается базовый класс (единственный), если он есть, потом через запятые интерфейсы, которые он реализует. Пример 4. Проект с геометрическими фигурами трех типов с интерфейсами вычисления площади и периметра. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Pattern5 { interface Space { double S(); // абстрактный метод вычисления площади для классов, реализующих интерфейс } interface Perimeter { double P(); // абстрактный метод вычисления периметра для классов, реализующих интерфейс } abstract class Figure // абстрактный класс для квадрата и треугольника { protected double X, Y, L; public Figure(double xx, double yy, double ll) { X = xx; Y = yy; L = ll; } public Double D() // обычная не абстрактная наследуемая функция { return Math.Sqrt(X * X + Y * Y); } } class Square : Figure,Space,Perimeter // производный от абстрактного класса // реализует интерфейсы площали и периметра { public Square(double xx, double yy, double ll) : base(xx, yy, ll) { } public double S() // реализация абстрактной функции из интерфейса { return L * L; } public double P() { return 4 * L; } } class Triangle : Figure, Space, Perimeter // производный от абстрактного класса // реализует интерфейсы площали и периметра { public Triangle(double xx, double yy, double ll) : base(xx, yy, ll) { } public double S() // реализация абстрактной функции из интерфейса { return L * L * Math.Sqrt(3.0) / 8; } public double P() { return 3 * L; } } class Ellipse : Space, Perimeter // реализует интерфейсы площали и периметра { private double a, b; // полуоси эллипса public Ellipse(double aa, double bb) { a = aa; b = bb; } public double S() // реализация абстрактной функции из интерфейса { return Math.PI*a*b; } public double P() { return Math.PI * (a + b); } } class Program { static void Main(string[] args) { double d, s, p; Triangle a = new Triangle(4, 3, 6); // new вызывает конструктор треугольника d = a.D(); s = a.S(); p = a.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); ; Square b = new Square(5, 12, 5); // new вызывает конструктор квадрата d = b.D(); s = b.S(); p = b.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Ellipse c = new Ellipse(5, 12); // new вызывает конструктор эллипса s = c.S(); p = c.P(); Console.WriteLine(" Площадь {0:f3}, Периметр {1:f3}", s, p); Console.ReadKey(); } } } 3) Пример использования паттерна фабричный метод на C# Фабричный метод (Factury method) - прием программирования, в котором создание объектов классов передается специальному классу, что дает гибкости в расширении проекта на новые классы. Рассмотрим проект на C#. Снова имеется абстрактный класс Figure, у которого 2 производных. В Figure имеются поля X,Y, L, которые наследуются в классах Square, Triangle. Кроме этого наследуется public метод D для вычисления расстояния от центра фигуры до начала координат. Методы вычисления площади S и периметра P абстрактны в базовом классе. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern6 { abstract class Figure // абстрактный класс { protected double X, Y, L; public Figure(double xx, double yy, double ll) { X = xx; Y = yy; L = ll; } public Double D() // обычная не абстрактная наследуемая функция { return Math.Sqrt(X * X + Y * Y); } public abstract double S(); public abstract double P(); // абстрактная функция // абстрактная функция } class Square : Figure // производный не абстрактный класс { public Square(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return L * L; } public override double P() // периметр фигуры квадрат перегружен { return 4 * L; } } class Triangle : Figure // производный не абстрактный класс { public Triangle(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return L * L * Math.Sqrt(3.0) / 8; } public override double P() // периметр фигуры треугольник перегружен { return 3 * L; } } class Program { static void Main(string[] args) { double d, s, p; Triangle a = new Triangle(4, 3, 6); // new вызывает конструктор треугольника d = a.D(); s = a.S(); p = a.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Square b = new Square(5, 12, 5); // new вызывает конструктор квадрата d = b.D(); s = b.S(); p = b.P(); Console.WriteLine("Расстояние:{0:f3} Площадь {1:f3}, Периметр {2:f3}", d, s, p); Console.ReadKey(); } } } Теперь определим фабричный метод. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern6 { public abstract class Figure // абстрактный класс { protected double X, Y, L; public Figure(double xx, double yy, double ll) { X = xx; Y = yy; L = ll; } public Double D() // обычная не абстрактная наследуемая функция { return Math.Sqrt(X * X + Y * Y); } public abstract double S(); public abstract double P(); // абстрактная функция // абстрактная функция } class Square : Figure // производный не абстрактный класс { public Square(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return L * L; } public override double P() // периметр фигуры квадрат перегружен { return 4 * L; } } class Triangle : Figure // производный не абстрактный класс { public Triangle(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return L * L * Math.Sqrt(3.0) / 8; } public override double P() // периметр фигуры треугольник перегружен { return 3 * L; } } // Добавление абстрактного фабричного метода и его производных. public abstract class FigureFactory { public abstract Figure CreateFigure(double xx,double yy,double ll); } public class SqureFactory : FigureFactory { public override Figure CreateFigure(double xx,double yy,double ll) { return new Square(xx,yy,ll); // теперь объекты через new создаются } } public class TriangleFactory : FigureFactory { public override Figure CreateFigure(double xx,double yy,double ll) { return new Triangle(xx,yy,ll); } } class Program { static void Main(string[] args) { FigureFactory squareFactory = new SqureFactory(); // Figure aSquare = squareFactory.CreateFigure(4,3,6); здесь, а не в main объект фабричного метода // задание объекта класса Square // через фабричный метод double s, p; s = aSquare.S(); p = aSquare.P(); Console.WriteLine(" Площадь {0:f3} Периметр {1:f3}", s, p); FigureFactory triangleFactory = new TriangleFactory(); Figure aTriangle = triangleFactory.CreateFigure(5,12,5); s = aTriangle.S(); p = aTriangle.P(); Console.WriteLine(" Площадь {0:f3} Периметр {1:f3}", s, p); Console.ReadKey(); } } } Таким образом имеются две иерархии классов: Figure FigureFactory Square Triangle SquareFactory TriangleFactory Несмотря на наличие дополнительных классов Factory такая система бывает выгодна для расширения методов класса или добавки нового класса. Например, требуется добавить круг. Figure Square Triangle Circle FigureFactory SquareFactory CircleFactory TriangleFactory class Circle : Figure // производный не абстрактный класс { public Circle(double xx, double yy, double ll) : base(xx, yy, ll) { } public override double S() // перегрузка абстрактной функции { return Math.PI*L*L; } public override double P() // периметр фигуры квадрат перегружен { return 2*Math.PI*L; } } public class CircleFactory : FigureFactory { public override Figure CreateFigure(double xx,double yy,double ll) { return new Circle(xx,yy,ll); } } static void Main(string[] args) { ………. FigureFactory circleFactory = new CircleFactory(); Figure aCircle = circleFactory.CreateFigure(5,12,5); s = aCircle.S(); p = aCircle.P(); Console.WriteLine(" Площадь {0:f3} Периметр {1:f3}", s, p); Console.ReadKey(); } 4) Порождающий паттерн Одиночка (Singleton) Одиночка - класс, для которого может быть создан только один объект. В стандартном варианте конструктор объявляется private, чтобы нельзя было использовать new в main. Поэтому объект создается через свойство (property). Кроме этого класс объявляется sealed, чтобы от него нельзя было наследовать другие классы. В классе создается единственный объект. При попытке создать объект класса сначала выполняется проверка, создан ли объект класса. Если не создан, он создается, иначе используется ранее созданный объект. Рассмотрим пример класса Circle. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace Patterns { public sealed class Circle { private static Circle instance; // единственный объект класса private Circle() { } // пустой конструктор private double r; // радиус public double S() { return Math.PI * r * r; } public double R { set { r = value; } get { return r; } } public static Circle Instance // свойство { get { if (instance == null) { instance = new Circle(); } return instance; } } } class Program { static void Main(string[] args) { double rad,s; String st; Circle c1 = Circle.Instance; Console.WriteLine("Введите радиус первого:"); // вывод строки st= Console.ReadLine(); // ввод строки rad = Convert.ToDouble(st); c1.R = rad; s = c1.S(); Console.WriteLine(" Площадь первого: {0:f3}", s); Circle c2 = Circle.Instance; Console.WriteLine("Введите радиус второго:"); st = Console.ReadLine(); // ввод строки rad = Convert.ToDouble(st); c2.R = rad; s = c2.S(); Console.WriteLine(" Площадь второго: {0:f3}", s); rad = c1.R; s = c1.S(); Console.WriteLine("Радиус первого: {0:f3} Площадь первого: {1:f3}",rad, s); Console.ReadKey(); } } } Второй круг как бы создается, но на самом деле это один круг, вводя радиус второго круга, на самом деле меняется у первого. Недостаток программы состоит в том, что если будет создано многопоточное приложение, то каждый поток может независимо проверить if (instance == null) и создать собственный объект. Стандартный прием Singlton на C# на примере Circle. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern8 { public sealed class Circle { public static int Number=0; // количество объектов private double r; // радиус private static Circle instance = new Circle(); private Circle() { Number++; // считает число объектов класса } public double S() { return Math.PI * r * r; } public double R { set { r = value; } get { return r; } } public static Circle Instance // свойство { get { return instance; } } } class Program { static void Main(string[] args) { double rad, s; String st; Circle c1 = Circle.Instance; // создание первого объекта Console.WriteLine("Введите радиус первого:"); // вывод строки st = Console.ReadLine(); // ввод строки rad = Convert.ToDouble(st); c1.R = rad; s = c1.S(); Console.WriteLine(" Площадь второго: {0:f3}", s); Circle c2 = Circle.Instance; Console.WriteLine("Введите радиус второго:"); st = Console.ReadLine(); // ввод строки rad = Convert.ToDouble(st); c2.R = rad; s = c2.S(); Console.WriteLine(" Площадь второго: {0:f3}", s); Console.WriteLine("Объектов: {0}", Circle.Number); if (c1==c2) { Console.WriteLine("Есть только один объект:"); } else { Console.WriteLine("Есть два объекта:"); } Console.ReadKey(); } } } 5) Структурный паттерн Заместитель (Proxy) Пример из жизни. Студента, который отсутствует на лекции, пытается имитировать другой студент, говоря его голосом. Main работает с заместителем, думая, что работает с настоящим объектом. Обычно используется, когда нет возможности работать с самим объектом. Пример паттерна. У абстрактного класса Figure с абстрактной функцией вычисления площади имеется производный класс квадрат Square со стороной a и перегруженной функцией вычисления площади. В main нет возможности создать объекты данного класса. Поэтому создан класс прямоугольник Rect, через который вычисляется площадь квадрата. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern { public abstract class Figure // абстрактный класс { public abstract double S(); // вычисление площади protected double a; // сторона фигуры public double A // свойство стороны { set { if (value > 0) a = value; } get { return a; } } } public class Square : Figure // не абстрактный класс квадрат { public override double S() // вычисление площади { return a * a; } } public class Rect:Figure // класс Proxy { private double b; // вторая сторона, которая не используется здесь public double B // property для b { set { if (value > 0) b = value; } get { return b; } } Figure fg; public override double S() { if(fg==null) { fg = new Square(); // создание квадрата fg.A = this.A; // задание ему длины стороны } return fg.S(); } } class Program { static void Main(string[] args) { Rect r = new Rect(); // объект заместитель Proxy r.A = 10; r.B = 15; double s; s = r.S(); // вызов площали, внутри создан квадрат и вычислена площадь Console.WriteLine(" Площадь квадрата: {0:f3}", s); Console.ReadKey(); } } } 6) Структурный паттерн Адаптер (Adapter) Пример. В некоторых зарубежных электрических приборах используется европейский разъем, который напрямую нельзя подключить к отечественной розетке. Подключается специальный переходник или адаптер. Имеется класс Rect прямоугольник с полями длинами сторон W, H. Имеется класс Calc, в котором функция S вычисляет площадь для своего аргумента прямоугольника. Эта функция не может вычислять площадь, если аргументом будет треугольник. Для вычисления пощади треугольника создается специальный класс CalcAdapter с функцией вычисления площади S, аргументом которой является объект треугольник. Внутри адаптера создается вспомогательный Rect для которого вычисляется площадь вспомогательного прямоугольника с половиной высоты исходного треугольника H using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern1 { class Rect { public double W; // стороны прямоугольника public double H; } class Calc { public double S(Rect r) // площадь прямоугольника r { return r.W * r.H; } } class Triangle { public double B; // основание треугольника public double H; // высота public Triangle(double b,double h) // конструктор { B = b; H = h; } } class CalcAdapter // Адаптер { public double S(Triangle t) // площадь для треугольника { Calc c = new Calc(); // объект площади прямоугольника Rect r=new Rect(); // прямоугольник равный половине высоты от исх. треугольника r.W = t.B; r.H = 0.5 * t.H; return c.S(r); // площадь прямоугольника, равная площади исх. треугольника } } class Program { static void Main(string[] args) { CalcAdapter cl = new CalcAdapter(); Triangle t = new Triangle(15, 20); double s; s = cl.S(t); // площадь треугольника через адаптер Console.WriteLine(" Площадь треугольника: {0:f3}", s); Console.ReadKey(); } } } 7) Поведенческий паттерн Посетитель (Visitor) Пример. В классе Circle, имеется поле radius и метод S(), вычисляющий площадь круга. По умолчанию радиус равен 5 и внктри класса менять его в классе невозможно. Поэтому, чтобы менять радиус создается класс Visitor, который реализует интерфейс IVisitor. В методе Visit и присваивается новое значение радиуса. Сам класс Circle также реализует интерфейс Circles с методом Accept(); using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace Pattern11 { interface Circles { void Accept(Visitor vs); // допуск посетителя в класс } public class Circle { private double radius = 5; // радиус по умолчанию, менять только через посетителя public double Radius { get { return radius; } set { radius = value; } } public double S() { return Math.PI * radius * radius; } public void Accept(Visitor vs) // допуск посетителя для замены радиуса { vs.Visit(this); } } interface IVisitor { void Visit(Circle c); } public class Visitor:IVisitor { double r; public Visitor(double rr) // конструктор посетителя { r = rr; } public void Visit(Circle c) // замена радиуса { c.Radius = r; } } class Program { static void Main(string[] args) { double s; Visitor vs = new Visitor(10); // посетитель с новым радиусом дл круга Circle c = new Circle(); s = c.S(); Console.WriteLine(" Площадь круга: {0:f3}", s); // площадь круга с радиусом по умолчанию 5. c.Accept(vs); // допус посетителя с новым радиусом s = c.S(); // площадь с новым радиусом Console.WriteLine(" Площадь круга: {0:f3}", s); Console.ReadKey(); } } } 8) Поведенческий паттерн Шаблонный метод (Template method) В базовом классе объявляются основные этапы алгоритма, в производных доопределяются некоторые методы по разному в каждом классе, так, чтобы основной алгоритм не менялся. Пример. Имеется абстрактный класс Figure с абстрактным методом SP(), который вычисляет площадь и периметр. Призводные классы Square и Circle перегружаюют этот метод. Шаблонный метод MainMethods вычисляет для каждой фигуры расстояние до центра координат, площадь и периметр. using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; namespace pattern12 { public abstract class Figure { protected double X=0,Y=0,L=0; public double p, s, d; public Figure(double x,double y,double l) { X = x;Y = y;L = l; } public void MainMethods() { Distance(out double d); SymmetryX(out X); SP(out s, out p); } private void Distance(out double dd) { dd = Math.Sqrt(X * X + Y * Y); d = dd; } private void SymmetryX(out double x) { x = -X; } public abstract void SP(out double s,out double p); } public class Square : Figure { public Square(double x,double y,double l):base(x,y,l) { } public override void SP(out double s, out double p) { s = L * L; p = 2 * L; } } public class Circle : Figure { public Circle(double x, double y, double l) : base(x, y, l) { } public override void SP(out double s, out double p) { s = Math.PI*L * L; p = 2 * Math.PI*L; } } class Program { static void Main(string[] args) { Square sq = new Square(3,5,7); sq.MainMethods(); Console.WriteLine("Расстояние: {0:f3} Площадь: {1:f3} Периметр: {2:f3}",sq.d, sq.s,sq.p); Circle cr = new Circle(2, 4, 6); cr.MainMethods(); Console.WriteLine("Расстояние: {0:f3} Площадь: {1:f3} Периметр: {2:f3}", cr.d, cr.s, cr.p); Console.ReadKey(); } } }
«Введение в паттерны проектирования» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Помощь с рефератом от нейросети
Написать ИИ

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot