В третьей главе рассматриваются базовые свойства акторов, описанные в PhD диссертации Gul Agha: каждый актор имеет адрес, большой почтовый ящик, куда доставляются сообщения, адресованные актору и поведение. В ответ на входящее сообщение актор может отправить конечный набор сообщений другим акторам и/или создать конечное число новых акторов и/или поменять свое поведение для обработки следующего сообщения.
В рамках данного курса будет разработана библиотека для разработки параллельных приложений на платформе .NET, построенная по модели акторов.
Исходные коды библиотеки будут выкладываться на GitHub: https://github.com/hwdtech/HWdTech.DS
Код библиотеки будет разработан с использованием следующих принципов, приемов и методик:
S.O.L.I.D. - принципы
Unit-tests
Mock
IoC контейнеры
Для удобства слушателей курса краткий обзор данных практик приведен в Главе 4.
13. Репозиторий GitHub 76
Библиотека акторов, котрая будет написана в
рамках спецкурса выложена по адресу
https://github.com/hwdtech/HWdTech.DS
14. S.O.L.I.D 77
• The Open-Closed Principle
• The Liskov Substitution
Principle
• The Interface Segregation
Principle
• The Dependency Inversion
Principle
• The Single Responsibility
Principle
objectmentor.com
Rob Martin (Uncle Bob)
15. The Open-Closed Principle 78
Программные объекты
должны быть открыты для
расширения, но в тоже
время закрыты для
модификации
16. Открытые vs закрытые 79
• Полиморфная
операция
• Паттерны
• DI контейнеры
• Код, ген. по
метаописанию
• switch
• If /else – if/else
• Неполиморфная
операция
• операторы
приведения типа
• enum
17. Открытые vs закрытые 80
• Полиморфная
операция
• Паттерны
• DI контейнеры
• Код, ген. по
метаописанию
• …
• Магические
константы
• Copy-paste
• Public поля
• Глобальные
переменные
18. Открытые vs закрытые 81
• Полиморфная
операция
• Паттерны
• DI контейнеры
• Код, ген. по
метаописанию
• …
• Магические
константы
• Copy-paste
• Public поля
• Глобальные
переменные
19. Программа Copy вер. 1 82
void Copy()
{
int ch;
while ((ch =
Keyboard()) != EOF)
{
WritePrinter(c);
}
}
enum OutputDevice
{
printer,
disk
};
void Copy(OutputDevice dev)
{
int c;
while ((c = ReadKeyboard()) != EOF)
{
if (dev == printer)
WritePrinter(c);
else
WriteDisk(c);
}
}
20. Программа Copy вер. 2 83
interface IReader
{
int Read();
}
interface IWriter
{
void Write(char) = 0;
}
void Copy(
IReader r,
IWriter w
)
{
int c;
while((c=r.Read()) !=
EOF)
w.Write(c);
}
22. The Dependency Inversion Principle85
Высокоуровневые компоненты не
должны зависеть от
низкоуровневых компонент. И те, и
те должны зависеть от
абстракций.
Абстракции не должны зависеть от
деталей. Детали должны зависеть
от абстракций.
26. Абстрактная фабрика 89
void Copy(
IReader r,
IWriter w
)
{
int c;
while((c=r.Read()) !=
EOF)
w.Write(c);
}
27. DI Container Autofac 90
var builder = new ContainerBuilder();
builder.RegisterType<LibraryBook>().As<IBook>();
builder.RegisterType<MainViewModel>().AsSelf();
var container = builder.Build();
var model = container.Resolve<MainViewModel>();
var view = new MainWindow (DataContext =
model);
view.Show();
29. Аксиомы и правила логики Хоара 92
Аксиома пустого оператора
{P} skip {P}
Аксиома присваивания
{P[E/x]} x := E {P}
Правило композиции
{P} S {Q}, {Q} T {R} ╞ {P} S;T {R}
Правило условного оператора
{B ^ P} S {Q}, {B’ ^P} T {Q} ╞ {P} if B then S else T endif {Q}
Правило вывода
P1 → P, {P} S {Q}, Q → Q1 ╞ {P1} S {Q1}
Правило оператора цикла
{P ^ B} S {P} ╞ {P} while B do S done {B’ ^ P}
30. Аксиомы и правила логики Хоара 93
Аксиома пустого оператора
{P} skip {P}
Аксиома присваивания
{P[E/x]} x := E {P}
Правило композиции
{P} S {Q}, {Q} T {R} ╞ {P} S;T {R}
Правило условного оператора
{B ^ P} S {Q}, {B’ ^P} T {Q} ╞ {P} if B then S else T endif {Q}
Правило вывода
P1 → P, {P} S {Q}, Q → Q1 ╞ {P1} S {Q1}
Правило оператора цикла
{P ^ B} S {P} ╞ {P} while B do S done {B’ ^ P}
31. Пример: pow(x,y) 94
http://freehabr.ru/blog/programming/1933.html
int power(int a, int n) {
assert(n > 0 || (a != 0 || n != 0));
if (n == 0) return 1;
else {
int a2 = power(a, n/2);
if (n & 1) return a*a2*a2;
else return a2*a2;
}
}
32. Пример: pow(x,y) 95
http://freehabr.ru/blog/programming/1933.html
int power(int a, int n) {
assert(n > 0 || (a != 0 || n != 0));
if (n == 0) return 1;
else {
int a2 = power(a, n/2);
if (n & 1) return a*a2*a2;
else return a2*a2;
}
}
33. pow(x,y) - итерация 96
int power(int a, int n) {
assert(n > 0 || (a != 0 || n != 0));
int r = 1, a0 = a, n0 = n;
/* r == 1 and a0 == a and n0 == n and n >= 0
инвариант_цикла: a0**n0 == r*a**n
ограничивающая_функция(n): n */
34. pow(x,y) - итерация 97
while(n > 0) {
/* n > 0 and ограничивающая_функция(n) > 0
and инвариант_цикла */
if (n & 1) r *= a;
/* (n - нечетно and a0**n0*a == r*a**n) or
инвариант_цикла */
n >>= 1;
35. pow(x,y) - итерация 98
/* n == 0
and инвариант_цикла
and ограничивающая_функция(n) == 0 */
// a0**n0 == r
return r;
}
36. Очень трудно! 99
Правило композиции
{P} S {Q}, {Q} T {R} ╞ {P} S;T {R}
Проверку каждого оператора
заменить на проверку группы
операторов
39. Следствия 102
Конструктор используется для
инвариантов класса
При нарушении условия выбрасывается
исключение
40. Следствия 103
Конструктор используется для
инвариантов класса
При нарушении условия выбрасывается
исключение
Техника RAII
41. Следствия 104
Конструктор используется для
инвариантов класса
При нарушении условия выбрасывается
исключение
Техника RAII
Модульное тестирование
44. Пример теста 107
Библиотека Nunit
using NUnit.Framework;
[TestFixture]
public class Tests {
[Test]
public void testStringReverse() {
String input = "abc";
String result = Util.reverse(input);
Assert.AreEquals("cba", result);
}
46. Недостатки 109
Тестирование основанное на состояниях:
• Требует знания о внутреннем состоянии
объекта –возможно нарушение
инкапсуляции
• Нарушает принципы ООП
• Некоторые вещи трудно тестировать:
закрытые свойства и методы,
алгоритмическую сложность
47. Но! А как же инкапсуляция? 110
Надо тестировать
не состояние, а
поведение!
48. Как тестировать поведение? 111
Полиморфизм: подменяя
поведение серверного кода
тестируем поведение
клиентского
49. Что тестировать? 112
Был ли вызван метод?
Сколько раз был вызван?
Порядок вызова методов
С какими параметрами?
Что вернул на выходе?
Выбросил ли исключение?
50. Пример Mock-теста 113
Библиотеки NUnit, Moq
[TestFixture]
public class ActorTests
{
MockRepository repository = new MockRepository(MockBehavior.Strict);
IMessage message;
[Test]
public void AnActorShouldHandleAMessage()
{
Mock<Actor> actor = repository.Create<Actor>();
actor.Setup(a => a.Handle(message)).Verifiable();
actor.Object.Receive(message);
actor.VerifyAll();
}
}
52. Необходимое условие 1 115
Принцип подстановки Лисков
Функции, которые используют
ссылки на базовые классы, должны
иметь возможность
использовать объекты
производных классов, не зная об
этом.
53. Необходимое условие 2 116
Принцип обращения зависимостей
Высокоуровневые компоненты не
должны зависеть от низкоуровневых
компонент. И те, и те должны
зависеть от абстракций.
Абстракции не должны зависеть от
деталей. Детали должны зависеть от
абстракций.