23 ноября 2011
Adapter pattern. Понимание важности.
Предположим, мы решили использовать уже готовую компоненту, тогда остается выбрать какую именно, но если выбор велик, то перед нами возникает проблема выбора, так как у каждой компоненты различные интерфейсы, различные характеристики по памяти/скорости работы, надежность, различная поддержка со стороны поставщика и цена. На изучении каждой у нас просто нет времени...
Итак, пришло время вспомнить о существовании такого шаблона проектирования как "Адаптер" (Adapter pattern). Я не буду здесь рассказывать про этот шаблон проектирования, а просто постараюсь выделить главную идею:
Всегда оборачивайте стороннюю компоненту своим интерфейсом и адаптируйте ее под себя.
Первая причина, почему это стоит делать очевидна - это устранение жестких зависимостей на стороннюю компоненту, а учитывая, что у зависимостей есть один неприятный момент: с ростом проекта они тоже разрастаются и чем дальше тем сложнее от них избавиться, и в конце концов можно стать "заложником" сторонней компоненты. Казалось бы простое правило, но на практике периодически сталкиваешься с обратным, да и сам порой забываешь обернуть, например, какой-нибудь logger, serializer(json, xml, yaml) или DI/IoC-контейнер, в надежде, что этот инструмент ты не сменишь никогда в проекте.
Вторая причина - это адаптация компоненты "под себя". Адаптируете компоненту таким образом, чтобы Вам было удобно ее использовать.
31 августа 2011
Mock для ICloneable типов
В моей ситуации, было все просто: метод Clone должен возвращать объект (которого на самом деле нет), с наперед известными данными (которые не подлежали бы изменениям). Для наглядности лучше привести исходный код.
Пусть это будет следующий интерфейс:
public interface ISome : ICloneable
{
// некое бизнес-поле
int Value { get; }
}
Итак, тесты вперед, поэтому напишем простой unit-test для метода Clone:
[TestMethod]
public void CloneTest()
{
var original = MakeMockCloneableSome();
// покажем, что и у клонированого объекта
// метод Clone работает как надо
var clone = (ISome)((ISome)((ISome)original.Clone()).Clone()).Clone();
// проверим, что бизнес поле совпадает
Assert.AreEqual(original.Value, clone.Value);
// проверим, что это 2 отдельных объекта
Assert.IsFalse(Object.ReferenceEquals(original, clone));
}
Осталось реализовать метод MakeMockCloneableSome():
ISome MakeMockCloneableSome()
{
var mock = new Mock<ISome>();
// Здесь привычный нам mock бизнес логики...
mock
.Setup(c => c.Value)
.Returns(123);
// Искомый mock метода ICloneable.Clone()
mock
.Setup(c => c.Clone())
.Returns(MakeMockCloneableSome);
return mock.Object;
}
12 мая 2011
Проверяем входные данные
class Bar {}
class Foo
{
Bar _bar;
public Foo(Bar bar)
{
// bar может быть null
if (bar == null)
throw new ArgumentNullException("bar");
_bar = bar;
}
}
14 апреля 2011
AOP средствами Unity 2.0
Unity 2.0 предоставляет нам три вида перехвата:
- InterfaceInterceptor для перехвата методов интерфейса
- VirtualMethodInterceptor для перехвата виртуальных методов
- TransparentProxyInterceptor для перехвата методов у объектов типа MarshalByRefObject
08 апреля 2011
Hello, Entity Framework "Code-First"
Предположим у нас имеется электронный магазин, в котором ведется два списка: список покупателей (Customers) и список заказов (Orders), которые храняться в базе данных ShopDb. Необходимо реализовать CRUD доступ над указанными сущностями в базе данных, используя весь потенциал Entity Framework 4.
Итак, в лучших традициях DDD начнем нашу работу с описания предметной области, для этого добавим в наш Solution проект (назовем его Domain), в который добавим два POCO (plain old CLR objects) класса Customer и Order, связанных отношением один-ко-многим:
public class Customer
{
public int CustomerId { get; set; }
public string ContactName { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public string Description { get; set; }
public Customer Customer { get; set; }
}
10 марта 2011
Caching в WCF сервисе
public DateTime GetDate()
{
ICache cache = ...; // получим экземпляр кэша
string key = "somekey";
object value;
// Попробуем достать данные из кэша
if (!cache.TryGet(key, out value))
{
// Данные в кэше отсутствуют,
// получим новые данные
value = DateTime.Now;
// и поместим их в кэш на 5 секунд
cache.Add(key, value, TimeSpan.FromSeconds(5));
}
return (DateTime)value;
}
Из примера видно, что сервис-метод GetDate перегружен логикой кэширования, и с появлением еще одного аналогичного сервис-метода, логика кэширования будет просто скопирована в него. Очевидно, что такой подход приведет к тому, что со временем такой код станет труднее поддерживать при изменении схемы кэширования, и естественно возникает вопрос об организации функционала сквозного кэширования. Организовать такую функциональность можно через AOP или в случае с WCF можно воспользоваться стандартным механизмом перехвата вызова через специальные интерфейсы (WCF Interceptor Interfaces), а точнее через интерфейс IOperationInvoker.
И, предже чем приступить к реализации наметим основные шаги:
- Для начала создадим простой WCF сервис
- Объявим интерфейс кэша ICache
- Реализуем свой перехватчик (IOperationInvoker)
- И закончим реализацией IOperationBehavior атрибута для нашего перехватчика
20 января 2011
IoC/DI в WCF на примере Unity 2.0
Итак, предже чем приступить к реализации наметим основные шаги:
- Для начала создадим простой WCF сервис
- Реализуем свой IInstanceProvider
- Далее опишем собственную реализацию IServiceBehavior
- Определим BehaviorExtensionElement
- И закончим, добавив необходимые настройки в web.config