tdd and decomposition

Post on 04-Dec-2014

1.860 Views

Category:

Technology

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

Presentation for XPDays Ukraine

TRANSCRIPT

Роль декомпозиции функционала

на отдельные классы при следовании TDD

Бибичев Андрей

декабрь 2011

bibigine

Андрей Бибичев

bull E-mail bibiginegmailcom

bull Twitter bibigine

bull Profile httptinyurlcombibigine

bull Slideshare httpwwwslidesharenetbibigine

Пример

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

bibigine

Андрей Бибичев

bull E-mail bibiginegmailcom

bull Twitter bibigine

bull Profile httptinyurlcombibigine

bull Slideshare httpwwwslidesharenetbibigine

Пример

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Пример

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

top related