tdd and decomposition
DESCRIPTION
Presentation for XPDays UkraineTRANSCRIPT
Роль декомпозиции функционала
на отдельные классы при следовании 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
Спасибо за внимание
Вопросы