O documento apresenta um resumo sobre padrões de projeto. Discute classificação de padrões, exemplos de Factory Method, Decorator, Observer e Strategy. Também aborda princípios SOLID e anti-padrões.
Design Patterns comC# Fernando Kakimoto [email_address] www.twitter.com/nandokakimoto
2.
Quem Sou Eu?Centro de Informática - U.F.P.E. Graduado em Ciências da Computação (2008) Mestrando em Ciências da Computação Inove Informática Engenheiro de Software / Líder de Equipe Certificações MCP | MCTS Web 2.0 SCJP 6.0 Intereseses Arquitetura, metodologias ágeis, desenvolvimento Web
Introdução “ Howcan you distribute responsibility for design through all levels of a large hierarchy, while still maintaining consistency and harmony of overall design?”
5.
Introdução Alexander sugeriuusar Padrões de Projeto Dicionário de termos relacionados a decisões básicas de projeto arquitetural Cada padrão descreve um problema comum do dia a dia e sua solução A solução pode ser reusada Discussões arquiteturais passaram a ser conduzidas por essa linguagem
Introdução “ Adesign pattern names, abstracts, and identifies the key aspects of a common design structure that make it useful for creating a reusable object-oriented design .” - Gang of Four (Gamma et al.)
8.
Por que padrões?Procurar objetos apropriados Determinar granularidade dos objetos Estimular reuso Projetar mudanças
9.
Nomenclatura Nome Contrução de um vocabulário Problema Quando aplicar o padrão Solução Estrutura genérica de elementos Consequências Trade-offs da implementação
Factory Method IntençãoMotivação Consequências Fornece uma interface para criação de famílias de objetos, sem especificar suas classes concretas A classe não pode antecipar o objeto que ela deve criar A classe precisa que a subclasse especifique o objeto criado Programação para interfaces Necessidade de subclasses Creator para criação de Products específicos
Factory Method publicinterface Manipulator { void DownClick(); void Drag(); void UpClick(); } public class LineManipulator : Manipulator { public void DownClick() { Console. WriteLine( "Line DownClick()" ); } public void Drag() { Console. WriteLine( "Line Drag()" ); } public void UpClick() { Console. WriteLine( "Line UpClick()" ); } } public class TextManipulator : Manipulator { public void DownClick() { Console. WriteLine( “Text DownClick()" ); } public void Drag() { Console. WriteLine( “Text Drag()" ); } public void UpClick() { Console. WriteLine( “Text UpClick()" ); } }
16.
Factory Method publicabstract class Figure { public Manipulator Manipulator { get; set; } public Figure() { CreateManipulator(); } public abstract void CreateManipulator(); public void DoSomething() { this .Manipulator.Drag(); } } public class LineFigure : Figure { public override void CreateManipulator() { this. Manipulator = new LineManipulator (); } } public class TextFigure : Figure { public override void CreateManipulator() { this .Manipulator = new TextManipulator (); } }
17.
Factory Method class Program { static void Main( string [ ] args) { Figure figure = new LineFigure (); figure.DoSomething(); figure = new TextFigure (); figure.DoSomething(); } }
18.
Decorator Intenção MotivaçãoConsequências Adiciona responsabilidades dinamicamente a um objeto Adicionar responsabilidades a objetos ao invés de classes Responsabilidades podem ser retiradas Quando extensão por herança é impraticável Mais flexibilidade do que heranças estáticas Evita explosão de classes Inúmeros objetos semelhantes
Decorator public abstractclass LibraryItem { public int NumCopies { get; set; } public abstract void Display(); } public class Book : LibraryItem { private string Author; private string Title; public Book( string author , string title , int numCopies) { this. Author = author; this. Title = title; this. NumCopies = numCopies; } public override void Display() { Console. WriteLine( "\n*** Book ***" ); Console. WriteLine( "Author: {0}" , Author); Console. WriteLine( "Title: {0}" , Title); Console. WriteLine( "#Copies: {0}" , NumCopies); } }
23.
Decorator public class Decorator : LibraryItem { protected LibraryItem LibraryItem { get; set; } public Decorator( LibraryItem libraryItem) { this. LibraryItem = libraryItem; } public override void Display() { LibraryItem.Display(); } } public abstract class LibraryItem { public int NumCopies { get; set; } public abstract void Display(); }
24.
Decorator class Program { static void Main( string [ ] args) { Book book = new Book( "Worley", "Inside ASP.NET" , 10); book.Display(); Borrowable borrowBook = new Borrowable (book); borrowBook.BorrowItem( "Customer #1" ); borrowBook.BorrowItem( "Customer #2" ); borrowBook.Display(); } } public class Borrowable : Decorator { public List < string > Borrowers { get ; private set ; } public Borrowable ( LibraryItem libraryItem ) : base (libraryItem) { this .Borrowers = new List < string >(); } public void BorrowItem( string name) { Borrowers.Add(name); this .LibraryItem.NumCopies- -; } public override void Display() { base. Display(); Borrowers.ForEach( b => Console.WriteLine ( "borrower: {0}" , b)); } }
25.
Observer Intenção MotivaçãoConsequências Define dependências entre objetos, tal que quando um objeto muda de estado, seus dependentes são notificados e atualizados Manter consistência entre objetos relacionados Manter baixo acoplamento Um objeto deve notificar outro objeto sem fazer suposições prévias Acoplamento abstrato entre Subject e Observer Suporte para comunicação broadcast Atualizações inesperadas
Observer public abstractclass Subject <T> { private List < Observer <T>> Observers; public Subject() { this .Observers = new List < Observer <T>>(); } public void Attach( Observer <T> o) { this .Observers.Add(o); } public void Detach( Observer <T> o) { this .Observers.Remove(o); } public void Notify(T data) { this .Observers.ForEach(o => o.Update(data)); } } public class ClockTimer : Subject < DateTime > { public DateTime CurrentTime { get; set; } public ClockTimer( DateTime time) { this. CurrentTime = time; } public void Tick() { this. CurrentTime = DateTime .Now; this .Notify( this .CurrentTime); } }
30.
Observer public interface Observer <T> { void Update(T data); } public class AnalogicTimer : Observer < DateTime > { public void Update( DateTime time) { Console .WriteLine( "AnalogicTimer {0}" , time); } } public class DigitalTimer : Observer < DateTime > { public void Update( DateTime time) { Console .WriteLine( "DigitalTimer {0}" , time); } }
31.
Observer class Program { static void Main( string [ ] args) { ClockTimer timer = new ClockTimer ( DateTime .Now); AnalogicTimer analogicTimer = new AnalogicTimer (); timer.Attach(analogicTimer); DigitalTimer digitalTimer = new DigitalTimer (); timer.Attach(digitalTimer); timer.Tick(); timer.Detach(analogicTimer); Thread .Sleep(5000); timer.Tick(); } }
32.
Strategy Intenção MotivaçãoConsequências Define uma família de algoritmos, encapsula cada um, e os torna substituíveis. Configurar uma classe com um entre vários comportamentos Diferentes variação para um mesmo algoritmo Encapsula detalhes de implementação de um algoritmo Define um comportamento para contextos de reuso Alternativa a extensão de classes Elimina instruções condicionais
Strategy public interface PersistenceStrategy <T> { void Save(T item); void Remove(T item); bool Exists(T item); } public class CollectionPersistence <T> : PersistenceStrategy <T> { public void Save(T item) { Console. WriteLine( "CollectionPersistence: Save" ); } public void Remove(T item) { Console .WriteLine( "CollectionPersistence: Remove" ); } public bool Exists(T item) { Console .WriteLine( "CollectionPersistence: Exists" ); return false; } }
37.
Strategy class Program { static void Main( string [ ] args) { Contact c = new Contact() { Name = "Fernando Kakimoto", PhoneNumer = "(81)9162-2997", Email = "[email protected]" }; PersistenceStrategy < Contact > persistence = new CollectionPersistence < Contact >(); persistence.Save(c); persistence.Remove(c); persistence.Exists(c); persistence = new DataBasePersistence < Contact >(); persistence.Save(c); persistence.Remove(c); persistence.Exists(c); } } public class DataBasePersistence <T> : PersistenceStrategy <T> { public void Save(T item) { Console .WriteLine( "DataBasePersistence: Save" ); } public void Remove(T item) { Console .WriteLine( "DataBasePersistence: Remove" ); } public bool Exists(T item) { Console .WriteLine( "DataBasePersistence: Exists" ); return false; } }
38.
SOLID Principles Expõeaspectos de gestão de dependência no desenvolvimento orientado à objetos Identifica código frágil e difícil de mudar/estender Base para as –ilities desejadas por desenvolvedores Março de 1995, Robert C. Martin
39.
SOLID Principles Single Responsability Principle O pen-Closed Principle L iskov Substituition Principle I nterface Segregation Principle D ependency Inversion Principle
40.
Single Responsability PrincipleUma classe deve ter uma única razão para mudar Uma responsabilidade é um eixo de mudança O que considerar como responsabilidade?
41.
Open-Closed Principle Entidadesde software devem ser abertas para extensões e fechadas para modificações Uma mudança deve ser concentrada, sem afetar demais módulos do sistema
42.
Liskov Substituition PrincipleSubclasses devem ser substituíveis por sua classe mãe Simples caso de violação do princípio Quadrado x Retângulo
43.
Interface Segregation PrincipleClientes não podem ser forçados a dependerem de interfaces que não usam Interfaces pequenas e especícias para clientes
Anti-Patterns Um padrãoque aponta como sair De um problema para uma solução ruim De uma solução ruim para uma solução boa Incentivados pela popularidade de Padrões de Projeto 1996, Michael Ackoyd - " AntiPatterns: Vaccinations Against Object Misuse "
46.
Anti-Patterns The BigBall of Mud Sistema sem arquitetura definida Overuse of Patterns Uso de Design Patterns sem necessidade God Objects Concentrar muitas responsabilidades à uma única classe Polter Geist Objetos usados apenas para passar informação
47.
Anti-Patterns Geographically DistributedDevelopment Integrantes de uma equipe geograficamente separados grande parte do tempo Accidental Complexity Introduzir complexidade desnecessária à solução Walking Through a Mine Field Incerteza sobre o comportamento de um componente Copy and Paste Programming Copiar código existente ao invés de criar soluções genéricas
Design Patterns comC# Fernando Kakimoto [email_address] www.twitter.com/nandokakimoto
Notas do Editor
#11 Escopo especifica se o padrão é aplicado ao objeto ou a classe. - classe: foca na relação de herança, fixos em tempo de compilação - objeto: foca na interação entre objetos, podendo ser mudados em tempo de execução Creational patterns abstract the object instantiation process: They hide how objects are created and help make the overall system independent of how its objects are created and composed. Structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities.