Міністерство освіти і науки України
НУ »Львівська політехніка»
Звіт 1
З дисципліни: Архітектура проектування ПЗ
Розробив:
Група ПІм-41з
Перевірив:
Климаш Т.С.
м. Хмельницький
2012
Тема: застосування шаблонів у ООП.
Мета: навчитись застосовувати шаблони у ООП.
Фабричний метод (Factory Method)
Опис
Фабричний метод застосовується для створення об'єктів з певним інтерфейсом, реалізації якого надаються нащадками.Шаблон використовується у випадках якщо:1. клас заздалегідь не знає, які об'єкти необхідно буде створювати, тому можливі варіанти реалізації;2. клас спроектований так, що специфікація породжуваного об'єкта визначається тільки в спадкоємцях.3. клас виділяє і делегує частину своїх функцій допоміжному класу. При цьому необхідно приховати його реалізацію для досягнення більшої гнучкості або можливості розширення функціональності.приклади реалізаціїАбстрактний метод або метод з інтерфейсуДаний підхід зобов'язує нащадка визначити свої реалізації Фабричного методу і породжуваного ним класу.Розглянемо на прикладі класу DocumentManager, відповідального за роботу з документом. Винесемо функції роботи з сховищем, збереження і завантаження документа, в окремий інтерфейс IDocStorage.
view source
print
public interface IDocStorage
{
void Save(string name, Document document);
Document Load(string name);
У класі DocumentManager додамо абстрактний Фабричний метод CreateStorage () для створення нового сховища. І, для прикладу його використання, напишемо метод Save (), що зберігає документ.01
public abstract class DocumentManager
{
public abstract IDocStorage CreateStorage();
public bool Save(Document document)
{
if (!this.SaveDialog()) {
return false;
}
// using Factory method to create a new document storage
IDocStorage storage = this.CreateStorage();
storage.Save(this._name, document);
return true;
} }
Визначимо нащадки класу DocumentManager, які будуть зберігати документи в txt і rtf форматах. Реалізації IDocStorage розмістимо в вкладених private класах. Це забезпечить потрібний рівень абстракції сховища, дозволивши клієнтського коду працювати з ними тільки через інтерфейс.Для стислості, в класів TxtDocStorage і RtfDocStorage прибраний код їх методов.01
public class TxtDocumentManager : DocumentManager
{
private class TxtDocStorage : IDocStorage { }
public override IDocStorage CreateStorage() { return new TxtDocStorage(); }
}
public class RtfDocumentManager : DocumentManager
{
private class RtfDocStorage : IDocStorage { }
public override IDocStorage CreateStorage() { return new RtfDocStorage(); }
}
Тепер результат виклику методу DocumentManager.CreateStorage () буде екземпляром TxtDocStorage або RtfDocStorage. Це буде визначатися в залежності від того, який нащадок абстрактного класу був створений. Значить виклик методу DocumentManager.Save () збереже дані у відповідному форматі. 1
// Save a document as txt file using "Save" dialog
DocumentManager docManager = new TxtDocumentManager();
docManager.Save(document);
// Or use the IDocStorage interface to save a document
IDocStorage storage = docManager.CreateStorage();
storage.Save(name, newDocument);
Одочка (Singleton)
Опис
Клас, що реалізує даний шаблон:1. гарантує, що можна створити тільки один його примірник;2. надає точку доступу для отримання цього примірника.Одинак використовується у випадку, якщо в системі необхідний об'єкт тільки в єдиному екземплярі. Наприклад ведення налагоджувальної інформації, реалізація сесій, кеш додатки, менеджер друку, доступ до апаратного забезпечення і т. д. Нерідко він використовується разом з іншими шаблонами (Абстрактної фабрикою, Будівельником і Прототипом) для забезпечення унікальності їх примірники.При проектуванні додатка варто врахувати і мінімізувати можливі негативні наслідки використання Одинаки. Вони є виявом його "глобалізації". Зокрема:Багато частині додатка стають залежні від нього і, побічно, один від одного. Це ускладнює внесення змін в подальшому. Полегшити ситуацію можна використовуючи Впровадження залежностей.Додаток стає складніше тестувати, тому дані, отримані від Одинаки, можуть бути створені в іншому модулі.Приклади реалізаціїРозглянемо один цікавий момент: єдиний екземпляр класу буде розміщений в статичної змінної. У. NET це забезпечить потокобезпечна його ініціалізації.Однак, залишається ще одна проблема: тип класу, що містить статичну змінну, отримає відмітку BeforeFieldInit. При її наявності, немає гарантій, в який момент будуть ініціалізований статичні поля класу (ECMA 335: специфікація CLI, розділ 8.9.5).Таким чином, не можна визначити, коли буде створений екземпляр Одинаки. Але є кілька підходів, що гарантують, що це відбудеться тільки при першому зверненні:для розміщення примірника Одинаки створюється вкладений клас зі статичним конструктором. Його наявність змусить компілятор не додавати позначку BeforeFieldInit. У цьому випадку, згідно специфікації, ініціалізація буде при першому зверненні.У. NET 4 можна використовувати клас Lazy.Розглянемо реалізації докладніше. При вивченні коду, зверніть увагу, що:код ініціалізації класу потокобезпечна;private-конструктор, по суті, забороняє створення спадкоємців. При цьому клас, для більшої наочності, можна відзначити як закритий (sealed);для поля _instance, що зберігає екземпляр класу, використовується ключове слово readonly. Це захистить його від можливості випадкової зміни в методах класу.
Реалізація з вкладеним классом01
/// <summary>Thread-safe singleton.</summary>
public sealed class Singleton
{
/// <summary>Initializes a new instance of the <see cref="Singleton"/> class.</summary>
private Singleton() { }
/// <summary>Gets the singleton instance.</summary>
public static Singleton Instance { get { return InstanceHolder._instance; } }
/// <summary>Using nested class as instance storage.</summary>
protected class InstanceHolder
{
/// <summary> Explicit static constructor to tell C# compiler
/// not to mark type as beforefieldinit.</summary>
static InstanceHolder() { }
/// <summary>The one and only instance of the Singleton class.</summary>
internal static readonly Singleton _instance = new Singleton();
} }
Реалізація для. NET 4 з використанням класу Lazy01
/// <summary>Thread-safe .NET4 lazy singleton.</summary>
public sealed class Singleton
{
/// <summary>The one and only instance of the Singleton class.</summary>
private static readonly Lazy<Singleton> _instance =
new Lazy<Singleton>(() => new Singleton());
/// <summary>Initializes a new instance of the <see cref="Singleton"/> class.
/// For internal use only.</summary>
private Singleton() { }
/// <summary>Gets the singleton instance.</summary>
public static Singleton Instance { get { return Singleton._instance.Value; } }
}
І в завершенні, ще один варіант реалізації. Це generic-клас, успадкування від якого робить з його нащадка одинак. За основу візьмемо версію з класом Lazy. Для виклику private конструктора використовуємо Reflection.
2. Реалізація generic-класу для шаблону Singleton01
/// <summary>Thread-safe singleton.</summary>
public class Singleton<T> where T : class
{
/// <summary>The one and only instance of the Singleton class.</summary>
private static readonly Lazy<T> _instance = new Lazy<T>(
() => (T)typeof(T).GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
null, new Type[0], null).Invoke(null));
/// <summary>Gets the singleton instance.</summary>
public static T Instance { get { return Singleton<T>._instance.Value; } }
Висновок: на лабораторній роботі ми навчитись застосовувати шаблони у ООП.