В ней были представлены 23 шаблона, ставших сейчас основными. Данная работа дала толчок к изучению паттернов программистами. Издание «банды четырех» (так в шутку прозвали авторов книги) до сих пор остается одним из ИТ-бестселлеров, и его постоянно публикуют.

В целом паттерны представляют собой некую архитектурную конструкцию, помогающую описать и решить определенную общую задачу проектирования. Они приобрели такую популярность потому, что разработка ПО ко времени их формализации уже была достаточно развита. Многие понимали, что не стоит изобретать велосипед, а использование паттернов часто бывает полезным как отдельному разработчику, так и целой команде.

Впрочем, применение шаблонов проектирования связано и с определенными проблемами. В частности, распространено мнение, что только специалист, обладающий достаточно высокой квалификацией и понимающий, какие из паттернов ему нужны, сумеет правильно использовать их в своих программах. Кроме того, зачастую некоторые разработчики, изучившие лишь несколько шаблонов проектирования, начинают употреблять их повсюду, даже там, где они не слишком хорошо справляются с задачей и усложняют создаваемое ПО.

«Банда четырех» разделила паттерны проектирования на три основные группы:

  • порождающие — призванные создавать объекты;
  • структурные — меняющие структуру взаимодействия между классами;
  • поведенческие — отвечающие за поведение объектов.

Кстати, в наши дни несложно выделить и другие группы и даже антипаттерны, подсказывающие, как не надо разрабатывать ПО.

Теперь выберем для обсуждения какой-нибудь паттерн, например абстрактную фабрику. Так, Abstract Factory — это один из самых известных порождающих шаблонов проектирования. Он позволяет разработчику создать интерфейс для объектов, каким-либо образом связанных между собой. Причем не требуется указывать конкретные классы, поскольку работать с каждым из них можно будет через этот интерфейс. С помощью такой фабрики удастся создавать группы объектов, реализующих общее поведение. Преимущество данного паттерна заключается в том, что он изолирует конкретные классы, благодаря чему легко заменять семейства продуктов. А к его недостаткам следует отнести то, что при расширении возможностей фабрики путем добавления нового типа продуктов придется редактировать все конкретные реализации Abstract Factory, а это порой бывает недопустимо, например, если уже создано 100 конкретных фабрик.

А теперь рассмотрим, как на практике можно использовать этот паттерн. Сначала создадим абстрактную фабрику CarFactory, содержащую семейство из двух объектов — автомобиля и двигателя для него.

  abstract class CarFactory 
  { 
    public abstract AbstractCar CreateCar(); 
    public abstract AbstractEngine CreateEngine(); 
  }

В результате у нас появился абстрактный класс с двумя методами, обеспечивающими получение соответствующих абстрактных объектов. Теперь реализуем первую конкретную фабрику, создающую класс, описывающий автомобиль BMW и двигатель для него:

class BMWFactory : CarFactory 
  { 
    public override AbstractCar CreateCar() 
    { 
      return new BMWCar(); 
    } 
public override AbstractEngine CreateEngine() 
    { 
     return new BMWEngine(); 
    } 
  }

Сделаем то же самое для автомобиля марки Audi, чтобы у нас возникла вторая конкретная фабрика:

class AudiFactory : CarFactory 
  { 
    public override AbstractCar CreateCar() 
    { 
     return new AudiCar(); 
    }    
public override AbstractEngine CreateEngine() 
    { 
     return new AudiEngine(); 
    } 
  }

Теперь опишем абстрактный класс для наших автомобилей. В данном случае у них будет один метод, позволяющий узнать максимальную скорость машины. С его помощью мы обратимся и ко второму объекту — двигателю:

 abstract class AbstractCar 
 {    
  public abstract void MaxSpeed(AbstractEngine engine); 
 }

Все двигатели, в свою очередь, будут содержать один параметр — максимальную скорость. Эта простая общедоступная переменная позволит сократить объем программы в данном примере:

 abstract class AbstractEngine 
  { 
     public int max_speed; 
  }

Реализуем класс для автомобиля BMW:

 class BMWCar : AbstractCar 
 {
public override void MaxSpeed(AbstractEngine engine)
{
Console.WriteLine(«Макcимальная скорость: « + engine.max_speed.ToString());

 }

А затем определяем параметры его двигателя:

class BMWEngine : AbstractEngine 
 {  
   public BMWEngine() 
 { 
    max_speed = 200; 
 } 
 }

Проделаем то же самое для класса, описывающего автомобиль Audi:

class AudiCar : AbstractCar 
  {
public override void MaxSpeed(AbstractEngine engine)
{
Console.WriteLine(«Макcимальная скорость: « + engine.max_speed.ToString());

}

Задаем двигатель для него:

class AudiEngine : AbstractEngine 
  {   
  public AudiEngine() 
  { 
    max_speed = 180; 
  } 
  }

Теперь мы создадим класс Client, где покажем, как осуществляется работа с абстрактной фабрикой. В конструктор такого класса будут передаваться все конкретные фабрики, которые и начнут создавать объекты автомобиль и двигатель. Следовательно, в конструктор класса Client допустимо передать любую конкретную фабрику, работающую с любыми марками автомобилей. А метод Run позволит узнать максимальную скорость конкретной машины.

 class Client 
 { 
   private AbstractCar abstractCar; 
private AbstractEngine abstractEngine; 
public Client(CarFactory car_factory) 
   { 
     abstractCar = car_factory.CreateCar(); 
     abstractEngine = car_factory.CreateEngine (); 
   }    
public void Run() 
   { 
      abstractCar.MaxSpeed(abstractEngine); 
    } 
  }

Ниже показано, как вызвать метод Run с различными параметрами:

   public static void Main() 
   { 
     // Абстрактная фабрика № 1 
CarFactory bmw_car = new BMWFactory (); 
     Client c1 = new Client(bmw_car); 
     c1.Run();     
// Абстрактная фабрика № 2      
CarFactory audi_factory = new AudiFactory();      
Client c2 = new Client(audi_factory);      
c2.Run(); 
     Console.Read(); 
    }

На этом мы сейчас закончим знакомство с абстрактной фабрикой. Чтобы получше разобраться с этим паттерном, рекомендую написать на его основе несколько программ, приняв для примера условие, что фабрика связана с какими-то бизнес-объектами. В следующей нашей статье мы продолжим изучение шаблонов проектирования.


Схема.

41302