handcode
bool good=true
среда, 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
пятница, 8 апреля 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