20
УК 03.002.01-2011 Учебный курс. Обучение. Контрактное программирование.

ук 03.002.01 2011

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: ук 03.002.01 2011

УК 03.002.01-2011 Учебный курс. Обучение.

Контрактное программирование.

Page 2: ук 03.002.01 2011

Базовые понятия

Page 3: ук 03.002.01 2011

Контрактная модель программирования

Б. Мейер Eiffel

Объект, предоставляющий ресурсы, называется сервером.

Объект, использующий ресурсы другого объекта, называется клиентом.

(КН 02.002-1999)

• Метафора условий и ответственности бизнес-контрактов.

• Контракт определяет ответственность объекта – поведение за которое он отвечает.

Page 4: ук 03.002.01 2011

Инвариант – логическое условие, значение которого не меняется.

• Asserts (жесткое падение)

• Тройка Хоара {pred} Action {post}

• Логика программирования

• Корректность программы

• Автоматическое тестирование

Предусловия – логическое условие, истинное до выполнения операции.

Постусловия – логическое условие, истинное после выполнения операции.

Page 5: ук 03.002.01 2011

• Нарушение инварианта – нарушает контракт абстракции

• Нарушено предусловие – клиент не соблюдает свои обязательства, и сервер не может выполнить операцию правильно

• Нарушено постусловие – свои обязательства нарушил сервер

• При нарушении какого-либо условия возбуждается исключительная ситуация (ПР 01.003)

• Конструктор используется для установки инвариантов класса (ПР 02.009)!!!

Page 6: ук 03.002.01 2011

Пример 1: Выделение класса

private FtpWebResponse _MakeRequest(string relativePath, string method, byte[] data)

{

FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create(GetPath(relativePath));

ftpWebRequest.Credentials = _credentials;

ftpWebRequest.Method = method;

ftpWebRequest.UsePassive = usePassive;

ftpWebRequest.ServicePoint.ConnectionLimit = 10;

if (data != null && data.Length > 0)

{

ftpWebRequest.ContentLength = data.Length;

using (Stream requestStream = ftpWebRequest.GetRequestStream())

{

requestStream.Write(data, 0, data.Length);

requestStream.Close();

}

}

return (FtpWebResponse)ftpWebRequest.GetResponse();

}

Page 7: ук 03.002.01 2011

• Требуется время на то, чтобы понять суть метода

• Нельзя повторно использовать для других типов запросов

• Название запутывает (MakeRequest, а надо MakeResponse)

• Смешение разных уровней абстракции

• Как следствие, несколько разных отвественностей, а значит потенциальные проблемы с замкнутостью

• Непонятно – что делать с ситуацией, когда тип запроса подразумевает данные в ответе, а их нет

Page 8: ук 03.002.01 2011

class Path

{

string normailizePath;

public Path(string relativePath)

{

normalizePath = GetPath(relativePath);

}

private void GetPath(string unnormalizedString)

{

}

public override string ToString()

{

return normalizePath;

}

}

private FtpWebResponse _MakeRequest(Path path, string method, byte[] data)

{

FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create(path.ToString());

ftpWebRequest.Credentials = _credentials;

ftpWebRequest.Method = method;

ftpWebRequest.UsePassive = usePassive;

ftpWebRequest.ServicePoint.ConnectionLimit = 10;

if (data != null && data.Length > 0)

{

ftpWebRequest.ContentLength = data.Length;

using (Stream requestStream = ftpWebRequest.GetRequestStream())

{

requestStream.Write(data, 0, data.Length);

requestStream.Close();

}

}

return (FtpWebResponse)ftpWebRequest.GetResponse();

}

Page 9: ук 03.002.01 2011

class Data

{ byte[] data;

public Data(byte[] exData)

{

if (null == exData)

throw ArgumentNullException();

if(0 == exData.Length)

throw new SomeException();

data = exData;

}

public byte[] Body

{

get

{

return data;

}

}

public int Length

{

get

{

return data.Length;

}

}

}

private FtpWebResponse _MakeRequest(Path path, string method , Data data)

{

FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create(path.ToString());

ftpWebRequest.Credentials = _credentials;

ftpWebRequest.Method = method;

ftpWebRequest.UsePassive = usePassive;

ftpWebRequest.ServicePoint.ConnectionLimit = 10;

if (data != null)

{

ftpWebRequest.ContentLength = data.Length;

using (Stream requestStream = ftpWebRequest.GetRequestStream())

{

requestStream.Write(data, 0, data.Length);

requestStream.Close();

}

}

return (FtpWebResponse)ftpWebRequest.GetResponse();

}

Page 10: ук 03.002.01 2011

private FtpWebResponse _MakeRequest(Path path, string method, Data data)

{

FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create(path.ToString());

ftpWebRequest.Credentials = _credentials;

ftpWebRequest.Method = method;

ftpWebRequest.UsePassive = usePassive;

ftpWebRequest.ServicePoint.ConnectionLimit = 10;

if (data != null)

{

ftpWebRequest.ContentLength = data.Length;

using (Stream requestStream = ftpWebRequest.GetRequestStream())

{

requestStream.Write(data, 0, data.Length);

requestStream.Close();

}

}

return (FtpWebResponse)ftpWebRequest.GetResponse();

}

private FtpWebResponse _MakeRequest(Path path, IResponseMethod method, Data data)

{

ResponseBuilder builder = new FTPResponseBuilder(this);

builder.Path = path;

method.Apply(builder);

if (data != null)

builder. Data = data;

return builder.GetResponse();

}

interface IResponseMethod

{

void Apply(IMethodHandler handler);

}

Interface IResponseHandler

{

void Handle(string method);

}

Page 11: ук 03.002.01 2011

• Фабрика билдеров

• ConnectionLimit из файла конфигурации

• Ограничить методы, соответствующим протоколом

Page 12: ук 03.002.01 2011

private WebResponse _MakeResponse(Path path,

IResponseMethod method)

{

ResponseBuilder builder = new FTPResponseBuilder(this);

builder.Path = path;

method.Apply(builder);

return builder.GetResponse();

}

interface IResponseMethod

{

void Apply(IMethodHandler handler);

}

Interface IResponseBuilder

{

void Handle(string method);

Data Data

{

set;

}

}

class ResposeWithBody: IResponseMethod

{

IResponseMethod method;

Data data;

public ResponseWithBody(IResponseMethod m, Data d)

{

if (null == d)

throw

ArgumentNullException();

method = m;

}

public override void Apply(ResponseBuilder builder)

{

method.Apply(builder);

builder.Data = data;

}

}

Page 13: ук 03.002.01 2011

Контракт метода в ООП

• возможные типы входных данных и их значение;

• типы возвращаемых данных и их значение;

• условия возникновения исключений, их типы и значения;

• присутствие побочного эффекта метода;

• предусловия, которые могут быть ослаблены (но не усилены) в подклассах (УК 02.001-2011, Принцип подстановки Лисков);

• постусловия, которые могут быть усилены (но не ослаблены) в подклассах (УК 02.001-2011, Принцип подстановки Лисков);

• инварианты, которые могут быть усилены (но не ослаблены) в подклассах;

• (иногда) качественные характеристики, такие как гарантии производительности, например, временная сложность или сложность по памяти

Page 14: ук 03.002.01 2011

RAII

RAII (Resource allocation is initialization) – выделение ресурса есть инициализация

• Адаптер для ресурса – класс, реализующий требуемое от ресурса поведение

• Конструктор используется для выделения ресурса

• Деструктор для освобождения

• Инвариант адаптера – ресурс выделен и находится в работоспособном состоянии

Page 15: ук 03.002.01 2011

RAII в .Net

• Неуправляемые ресурсы

• IDisposable

• Инструкция using

Page 16: ук 03.002.01 2011

using vs. try-finally

using (A a = new A())

{

}

try

{

A a = new A();

}

finally

{

a.Dispose();

}

Page 17: ук 03.002.01 2011

Пример 2: Курсор Песочные часы

void f()

{

Cursor previous = Cursor.Current;

Cursor.Set(Cursor.Wait);

try

{

throw …

}

finally

{

Cursor.Set(previous);

}

if (…)

{

Cursor.Set(previous);

return file2;

}

f (…)

{

Cursor.Set(previous);

return file;

}

}

class MyCursor: IDisposable

{

Cursor previous;

public MyCursor()

{

Cursor previous = Cursor.Current;

Cursor.Set(Cursor.Wait);

}

public void Dispose() { Dispose(true); }

void Dispose(bool disposed)

{

….

Cursor.Set(previous);

}

}

void f()

{

using (MyCursor cursor = new MyCursor)

{

throw …

if (…)

{ return file2; }

if (…)

{ return file; }

}

}

Page 18: ук 03.002.01 2011

delegate D(); class CursorExtender { public static void WaitingAction(D d) { Cursor previous = Cursor.Current; Cursor.Set(Cursor.Wait); try { d(); } finally { Cursor.Set(previous); } } } void f() { Cursor.WaitingAction( new delegate{ { throw … if (…) { return file2; } if (…) { return file; } } ); }

Page 19: ук 03.002.01 2011

Что дальше

• Юнит-тестирование

• Интеграционные тесты

• Приемочные тесты

Page 20: ук 03.002.01 2011

Вопросы?