Разделы презентаций


SOLID и инверсия зависимостей

Содержание

О пользе проектированияИзначально любая система обладает некоторой гибкостью (agility), другими словами, способностью к изменению. В процессе поступления новых требований от заказчика (change requests) ее гибкость падает до некоторого предела, называемого параличом

Слайды и текст этой презентации

Слайд 1SOLID
Принципы проектирования программ

SOLIDПринципы проектирования программ

Слайд 2О пользе проектирования
Изначально любая система обладает некоторой гибкостью (agility), другими

словами, способностью к изменению. В процессе поступления новых требований от

заказчика (change requests) ее гибкость падает до некоторого предела, называемого параличом (paralyses). Вход в стадию паралича означает:
Вносить изменения стало слишком дорого;
Вносить изменения стало невозможно из-за высокой сложности системы.

Паралича избежать невозможно, однако его можно максимально оттянуть, используя хорошую архитектуру.

О пользе проектированияИзначально любая система обладает некоторой гибкостью (agility), другими словами, способностью к изменению. В процессе поступления

Слайд 3S O L I D

S  O  L  I  D

Слайд 4Принцип единственной обязанности
Каждый интерфейс должен отвечать за что-то одно.

Индикатор

ответственности – повод для изменений. Если есть несколько поводов для

изменения, интерфейс совмещает несколько обязанностей.

Пример: класс для составления и печати отчета – должен быть один класс для составления и другой класс для печати.

То же относится и к методам – каждый метод должен делать что-то одно.

Принцип единственной обязанностиКаждый интерфейс должен отвечать за что-то одно. Индикатор ответственности – повод для изменений. Если есть

Слайд 5Принцип открытости-закрытости
Модуль или класс должен быть закрыт для изменений и

открыт для дополнений.
Иными словами, изменения программы должны происходить за счет

дописывания нового кода, а не переписывания того, что уже работает.

Соблюсти принцип можно, добавляя новую функциональность в классы-наследники, при этом оставляя неизменными классы-предки (допускается и простое добавление новых методов в класс).

Другая формулировка основана на использовании абстракций. Класс А должен зависеть не от класса В, а от интерфейса IB, который реализуется классом B.

Изменить поведение А можно, дав новую реализацию интерфейса IB, при этом код класса А не изменится.

Бертран Мейер

Роберт Мартин

Принцип открытости-закрытостиМодуль или класс должен быть закрыт для изменений и открыт для дополнений.Иными словами, изменения программы должны

Слайд 6class Picture
{
List figures;

public void Print()
{
foreach

(var f in figures) {
if (f is

Rectangle)
Console.Write((Rectangle)f.Info());

if (f is Square)
Console.Write((Square)f.Info());
}

}

Пример

Классы Фигура, Окружность, Прямоугольник и контейнер Рисунок.

Это плохое проектирование.

class Rectangle: Figure
{
int w, h;
public Rectangle(int x, int y, int w, int h)
{
X = x; Y = y; this.w = w; this.h = h;
}
public int S { get { return w * h; } }
public string Info()
{
return string.Format("x={0} y={1} w={2} h={3} ",
X, Y, w, h);
}
}

class Figure
{
public int X {set; get;}
public int Y {set; get;}
}

class Square: Figure
{
int w;

public Square(int x, int y, int w)
{
X = x; Y = y; this.w = w;
}
public int S { get { return w * w; } }
public string Info()
{
return string.Format("x={0} y={1} w={2}", X, Y, w);
}
}

class Picture{ List figures; public void Print() {  foreach (var f in figures) {

Слайд 7abstract class Figure
{
public int X { set; get;

}
public int Y { set; get; }

public int S { get; }
public string Info();
}

class Rectangle : Figure
{
int w, h;
public Rectangle(int x, int y, int w, int h)
{
X = x; Y = y; this.w = w; this.h = h;
}
public override int S { get { return w * h; } }
public override string Info()
{
return string.Format("x={0} y={1} w={2} h={3} ",
X, Y, w, h);
}
}

class Square : Figure
{
int w;

public Square(int x, int y, int w)
{
X = x; Y = y; this.w = w;
}
public override int S { get { return w * w; } }
public override string Info()
{
return string.Format("x={0} y={1} w={2}", X, Y, w);
}
}

Пример (продолжение)

class Picture
{
List

figures;

public void PrintInfo()
{
foreach (var f in figures)
Console.WriteLine(f.Info());
}

public int S()
{
return figures.Sum(f => f.S);
}
}

Класс Picture зависит от абстракции. Изменение реализации конкретных фигур, даже появление новых фигур не меняют код Picture.


Слайд 8Принцип подстановки
Функции, которые используют базовый тип, должны иметь возможность использовать

подтипы базового типа даже не зная об этом.
 Барбара Лисков
Определение подтипа:

Тип S будет подтипом Т тогда и только тогда, когда соблюдает принцип подстановки.

Язык C++ не поддерживает принцип подстановки, а C# и Java поддерживают.


Вопрос. Если при реализации интерфейса IList метод Insert() будет добавлять не один, а два дубликата экземпляра, нарушится принцип подстановки?

Принцип подстановкиФункции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа даже не зная об

Слайд 9 Контракт = Интерфейс
Программирование по контракту
+ Предусловия
+ Постусловия
+ Инварианты
Предусловия

– это ограничения, которые накладываются на входные параметры и внешние

переменные методов, например, функция Gcd(a, b), которая находит НОД, требует, чтобы a >= 0, b >= 0 и a <=b.

Постусловия – это ограничения, которые накладываются на возвращаемые значения методов, выходные параметры, и состояние внешних переменных после завершения метода. Например, если r - наибольший общий делитель, то r > 0 && r <=b.

Инварианты – это условия, которые относятся к классу в целом и должны выполняться на всем протяжении жизни экземпляра класса. Например, в классе List объем захваченной памяти больше или равен объему памяти, занятому данными, а в классе SortedList данные к тому же всегда упорядочены. Инвариант – это и пред- и постусловие одновременно.
Кроме того, инварианты, как часть контракта, наследуются производными классами.
Контракт = ИнтерфейсПрограммирование по контракту+ Предусловия	+ Постусловия+ Инварианты Предусловия – это ограничения, которые накладываются на входные

Слайд 10Контракты в .NET
http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx
Библиотека и статический класс Contract.
Преобразователь кода – ccrewrite.exe.
Анализатор

кода – cccheck.exe.
Первая часть это библиотека. Контракты кодируются с использованием

вызова статических методов класса Contract (пространство имен System.Diagnostics.Contracts) из сборки mscorlib.dll. Контракты имеют декларативный характер, и эти статические вызовы в начале тела метода можно рассматривать как часть сигнатуры метода. Они являются методами, а не атрибутами, поскольку атрибуты очень ограничены, но эти концепции близки.

Вторая часть это binary rewriter, ccrewrite.exe. Этот инструмент модифицирует инструкции MSIL и проверяет контракт. Это инструмент дает возможность проверки выполнения контрактов, чтобы помочь при отладке кода. Без него, контракты просто документация и не включается в скомпилированный код.

Третья часть это инструмент статической проверки, cccheck.exe, который анализирует код без его выполнения и пытается доказать, что все контракты выполнены.
Контракты в .NEThttp://msdn.microsoft.com/en-us/devlabs/dd491992.aspxБиблиотека и статический класс Contract.Преобразователь кода – ccrewrite.exe.Анализатор кода – cccheck.exe.Первая часть это библиотека. Контракты

Слайд 11Code Contracts в Студии

Code Contracts в Студии

Слайд 12// Прямоугольник с фиксированным периметром и шириной больше высоты.

class MyRect
{
double p,

w, h;
[ContractInvariantMethod]
void ObjectInvariant()
{
Contract.Invariant(p == w + h);
Contract.Invariant(w >= h);
Contract.Invariant(h > 0);
}
public MyRect(double w, double h)
{
this.w = w;
this.h = h;
p = w + h;
}
public double H
{
// Изменение высоты не должно превышать 10 единиц за раз.
set {
// Проверка в форме предусловия.
Contract.Requires(Math.Abs(value - H) < 10.0, "Too large change.");
h = value;
w = p - h;
}
get { return h; }
}
public double W
{
// Изменение ширины не должно превышать 10 единиц за раз.
set
{
// Проверка в форме постусловия.
Contract.Ensures(Math.Abs(Contract.OldValue(w) - w) < 10.0, "Too large...");
w = value;
h = p - w;
}
get { return w; }
}
public double Square()
{
// Площадь всегда положительна.
Contract.Ensures(Contract.Result() > 0, "Squere must be positive");
return w * h;
}
}

Пример


Слайд 13Принцип разделения интерфейсов
Принцип разделения интерфейсов говорит о том, что слишком

«толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы

клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе.

В итоге, при изменении метода интерфейса не будут меняться клиенты, которые этот метод не используют.

Клиенты не должны зависеть от методов, которые они не используют.

Принцип разделения интерфейсовПринцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие

Слайд 14Принцип инверсии зависимостей
Зависимости внутри системы строятся на основе абстракций (т.е.

интерфейсов).

Модули верхнего уровня не зависят от модулей нижнего уровня.


Принцип инверсии зависимостейЗависимости внутри системы строятся на основе абстракций (т.е. интерфейсов). Модули верхнего уровня не зависят от

Слайд 15Пример зависимости
// Воин владеет оружием
public class Warrior
{
readonly Sword

weapon;

// Оружие получает при рождении
public Warrior(Sword

weapon)
{
this.weapon = weapon;
}
// При помощи оружия может и убить
public void Kill()
{
weapon.Kill();
}
}

// Меч способен убивать
public class Sword
{
public void Kill()
{
Console.WriteLine("Chuk-chuck");
}
}

Warrior

Sword


class Program
{
static void Main()
{
Warrior warrior = new Warrior(new Sword());
warrior.Kill();
}
}

Есть два класса – Воин и Меч. Воин владеет мечем, а значит, зависит от него.

Пример зависимости// Воин владеет оружиемpublic class Warrior{  readonly Sword weapon;  // Оружие получает при рождении

Слайд 16Инверсия зависимости

IWeapon
Warrior
Sword
x
// Оружие способно убивать
public interface IWeapon

{
void Kill();
}
// Базука – оружие,

поэтому способна убивать
public class Bazuka : IWeapon
{
public void Kill()
{
Console.WriteLine("BIG BADABUM!");
}
}

// Меч – оружие, поэтому способен убивать
public class Sword : IWeapon
{
public void Kill()
{
Console.WriteLine("Chuk-chuck");
}
}

Воин зависит от абстракции.
И меч зависит от абстракции.
От меча воин не зависит.

Инверсия зависимостиIWeaponWarriorSwordx // Оружие способно убивать public interface IWeapon {   void Kill(); } // Базука

Слайд 17Код после инверсии зависимости
public class Warrior
{

readonly IWeapon weapon;

public Warrior(IWeapon weapon)

{
this.weapon = weapon;
}
public void Kill()
{
weapon.Kill();
}
}

class Program
{
static void Main()
{
Warrior warrior = new Warrior(new Sword());
warrior.Kill();
}
}

public interface IWeapon
{
void Kill();
}

public class Sword : IWeapon
{
public void Kill()
{
Console.WriteLine("Chuk-chuck");
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IoC
{
public interface IWeapon
{
void Kill();
}

public class Warrior
{
readonly IWeapon weapon;

public Warrior(IWeapon weapon)
{
this.weapon = weapon;
}
public void Kill()
{
weapon.Kill();
}
}

public class Sword : IWeapon
{
public void Kill()
{
Console.WriteLine("Chuk-chuck");
}
}

class Program
{
static void Main()
{
Warrior warrior = new Warrior(new Sword());
warrior.Kill();
}
}
}

Код после инверсии зависимости public class Warrior {   readonly IWeapon weapon;   public Warrior(IWeapon

Слайд 18IoC-контейнер
IoC контейнер - это служба для управления созданием объектов.

Составные части

контейнера:
Регистратор реализаций
Фабрика объектов

Alpha --> IAlpha
Beta --> IBeta
Sword -->

IWeapon


Фабрика объектов

IWeapon

Sword

IoC-контейнерIoC контейнер - это служба для управления созданием объектов.Составные части контейнера:Регистратор реализацийФабрика объектовAlpha --> IAlphaBeta --> IBeta

Слайд 19Пакет Ninject и его установка
Меню: TOOLS / Library Package

Manager / Package Manager Console

или

Команда в PM-консоли: PM> Install-Package

Ninject
Пакет Ninject и его установкаМеню:  TOOLS / Library Package Manager / Package Manager ConsoleилиКоманда в PM-консоли:

Слайд 20Ninject в настольном приложении
using Ninject.Modules;

public class

WeaponNinjectModule : NinjectModule
{
public override void Load()

{
// Регистрация реализации
this.Bind().To();
}
}

using Ninject;

class Program
{
public static IKernel AppKernel;

static void Main()
{
// Фабрика объектов
AppKernel = new StandardKernel(new WeaponNinjectModule());
var warrior = AppKernel.Get();
}
}

Ninject в настольном приложении using Ninject.Modules;  public class WeaponNinjectModule : NinjectModule {   public override

Слайд 21Атрибут [Inject]
public class Warrior
{

[Inject]
public IWeapon Weapon {

set; get; }

public void Kill()
{
Weapon.Kill();
}
}

public class Warrior
{
readonly IWeapon weapon;

public Warrior(IWeapon weapon)
{
this.weapon = weapon;
}

public void Kill()
{
weapon.Kill();
}
}

Ninject инициализирует автоматические свойства, если они открытые и помечены атрибутом [Inject]

Версия класса Warrior со свойством Weapon

Версия класса Warrior с полем weapon

Атрибут  [Inject]  public class Warrior  {    [Inject]    public

Слайд 22Самостоятельно
Объект ScheduleViewer показывает расписание, придав ему эстетический вид.

Он получает

расписание в сыром виде при помощи объекта ScheduleManager

Преобразуйте заданный код,

внедрив зависимость от интерфейса и применив IoC-контейнер для создания объектов.

class ScheduleManager
{
public String GetSchedule()
{
return "1,2,3";
}
}

class ScheduleViewer
{
ScheduleManager _scheduleManager;

public ScheduleViewer(ScheduleManager scheduleManager)
{
_scheduleManager = scheduleManager;
}

public string RenderSchedule()
{
return "<" + _scheduleManager.GetSchedule() + ">";
}
}

class Program
{
static void Main(string[] args) {
ScheduleViewer sv = new ScheduleViewer(new ScheduleManager());
Console.WriteLine(sv.RenderSchedule());
}
}

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

Обратная связь

Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика