Mikhail Valkov_Antipatterns
description
Transcript of Mikhail Valkov_Antipatterns
АНТИПАТЕРНЫ ПРОГРАММИРОВАНИЯ2011
Part 1
• What is patterns ?• Patterns for patterns• Target patterns• Structural patterns• Creational patterns• Optimization example
• Дубликаты кода• Большая вложенность внутри
метода• Магические константы• Суперклассы, интерфейсы,
методы• Public только для тестов
Structural patterns
Proxy
Adapter
Facade
Bridge
Decorator
Composite
Structural patternsProxyСлужит для управления доступом к заданному объекту, перехватывая вызовы к нему. Ни интерфейс ни функциональность замещенного компонента, для клиента, не должна изменяются.
Используется:• работа с объектом не должна зависеть от того, где он
реально расположен
Structural patternsAdapterСлужит для приведения интерфейса объекта к требуемому виду.
• существующий объект, называемый адаптируемым, предоставляет необходимые функции, но не поддерживает нужного интерфейса;
• неизвестно заранее, с каким интерфейсами придется работать адаптируемому объекту;
Structural patternsFacadeОбъединяет группу объектов в рамках одного специализированного интерфейса и переадресует вызовы его методов к этим объектам.
Используется:• упростить доступ к сложной системе;• создать различные уровни доступа к системе;
Structural patternsBridgeПозволяет разделить объект на абстракцию и реализацию так, чтобы они могли изменяться независимо друг от друга.
Используется:• независимо изменять интерфейс работы с клиентом и
реализацию;• выбирать реализацию в процессе работы программы;
Structural patternsDecoratorДекоратор предназначен для динамического добавления объекту новой функциональности.
Используется:• динамически и прозрачно для клиента изменять
функциональность объекта;• реализовать небольшую функциональность, которая в
дальнейшем может быть исключена;
Structural patternsCompositeПозволяет упростить и стандартизировать взаимодействие между клиентом и группой объектов, представляющих древовидную структуру или части составного объекта.Используется:• представить группу объектов в виде "составной объект –
его части";• для обращения как к составным объектам, так и к
отдельным частям.
Creational patterns
Singleton
Multiton
Object pool/Cache
Prototype
Builder
Creational patternsSingletonПредоставляет доступ к объекту
public sealed class Singleton { private static Singleton instance;
private Singleton() { }
public static Singleton Instance { get { return instance ?? (instance = new Singleton()); } }}
Creational patternsSingletonpublic class Singleton<T> where T : class{ private static readonly Lazy<T> instance = new Lazy<T>( () => (T)typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], null).Invoke(null));
public static T Instance { get {
return instance.Value; } }
}
Creational patternsMultitonСоздаёт определенное число своих экземпляров и предоставляет точку доступа для работы с ними. Каждый экземпляр связан с уникальным идентификатором.
public sealed class Multiton<TKey> { private static readonly ConcurrentDictionary<TKey, Multiton<TKey>> instances = new ConcurrentDictionary<TKey, Multiton<TKey>>();
private Multiton(TKey key) { /* ... */ }
public static Multiton<TKey> GetInstance(TKey key) { return instances.GetOrAdd(key, x => new Multiton<TKey>(x)); } }
Creational patternsObject poolПредназначен хранения готовых к использованию объектов. Когда системе требуется новый объект, он запрашивается из Пула, минуя процесс порождения. А после использования возвращается обратно в Пул вместо уничтожения.
Используется:• объекты часто создаются и уничтожаются;• создание/уничтожение объекта являются очень затратными
операциями.
Creational patternsObject pool/Cache
public interface IPoolObjectCreator<out T>{ T Create();}
public class DefaultObjectCreator<T> : IPoolObjectCreator<T> where T : class, new(){ T IPoolObjectCreator<T>.Create() { return new T(); }}
public class ObjectPool<T> where T : class, IPoolable{ private readonly ConcurrentBag<T> container = new ConcurrentBag<T>();}
Creational patternsPrototypeПозволяет создавать новые объекты путем клонирования уже существующих.Используется:• система не должна зависеть от способа создания и
реализации входящих в нее объектов;• класс порождаемого объекта определяется в момент
выполнения;public abstract class SimpleElement{ public uint Id { get; set; }
public string Title { get; set; }
public virtual SimpleElement Clone() { return (SimpleElement)this.MemberwiseClone(); }}
Creational patternsPrototypepublic abstract class SimpleElement{ public Guid Id { get; set; }
public string Title { get; set; }
public virtual SimpleElement Clone() { return (SimpleElement)this.MemberwiseClone(); }}
public void CopyObjects(IEnumerable<SimpleElement> selectedElements){
foreach (SimpleElement element in selectedElements) { SimpleElement newElement = element.Clone(); newElement.Id = Guid.NewGuid(); this.AddNewElement(newElement);
}}
Creational patternsBuilderПозволяет отделить процесс создания сложного объекта от его реализации. При этом, результатом одних и тех же операций могут быть различные объекты.
Используется:• алгоритм этого процесса не должен зависеть от того, из
каких частей состоит объект;• конструирование должно обеспечивать возможность
создавать различные объекты.
Factory MethodПрименяется для создания объектов с определенным интерфейсом или абстрактным классом, реализации
которого предоставляются потомкам.
Abstract Factory
Factory
Factory Method
public interface IDataStorage { void Save(Stream stream);
Stream Load(); } public abstract class DocumentManager{ public abstract IDataStorage CreateStorage();} public class FileStorageManager : DocumentManager { private class FileStorage : IDataStorage { /* … */ } public override IDataStorage CreateStorage() { return new FileStorage(); } }
public class MemeoryStorageManager : DocumentManager { private class MemeoryStorage : IDataStorage { /* … */ } public override IDataStorage CreateStorage() { return new MemeoryStorage(); } }
Factory MethodРЕАЛИЗАЦИЯ
public enum StorageFormat{ File,
Memory}
static void Main(string[] args){ IDataStorage storage = CreateStorage(StorageFormat.Memory); storage.Load();}
static IDataStorage CreateStorage(StorageFormat format){ switch (format) { case StorageFormat.Memory: return new FileStorageManager().CreateStorage(); case StorageFormat.File: return new MemeoryStorageManager().CreateStorage(); default: throw new ArgumentException("Invalid format: " + format); }}
Factory Methodиспользование
public enum StorageFormat{ File,
/* . . . */
Memory}
static void Main(string[] args){ IDataStorage storage = CreateStorage(StorageFormat.Memory); storage.Load();}
static IDataStorage CreateStorage(StorageFormat format){ switch (format) { case StorageFormat.Memory: return new FileStorageManager().CreateStorage(); /* . . . */
case StorageFormat.File: return new MemeoryStorageManager().CreateStorage(); default: throw new ArgumentException("Invalid format: " + format); }}
Factory Methodк чему это приводит
private delegate IDataStorage MakeStorageHandler();
private static readonly IDictionary<StorageFormat, MakeStorageHandler> storageMaker = new Dictionary<StorageFormat, MakeStorageHandler> { { StorageFormat.File, () => new FileStorageManager().CreateStorage() }, { StorageFormat.Memory, () => new MemeoryStorageManager().CreateStorage() } };
static IDataStorage CreateStorage(StorageFormat format){ if (storageMaker.ContainsKey(format)) { return storageMaker[format](); }
throw new ArgumentException("Invalid format: " + format);}
Factory Methodпример решения
public enum StyleType{ [StringValue("Grid")] Grid,
[StringValue("Grid View")] GridView,
[StringValue("Grid List")] GridList,}
public static string GetStringValue(this Enum @enum){ Type type = @enum.GetType(); MemberInfo[] memberInfo = type.GetMember(@enum.ToString());
if (!memberInfo.IsNullOrEmpty()) { object[] attributes = memberInfo[0].GetCustomAttributes(typeof(StringValueAttribute), false); if (!attributes.IsNullOrEmpty()) { return ((StringValueAttribute)attributes[0]).Value; } }
return @enum.ToString();}
Factory Methodработа с ключом