Абстрактна Фабрика (шаблон)

Абстрактна фабрика е създаващ шаблон за дизайн, който се използва в обектно-ориентираното програмиране.

Фабриката е средство за създаване на обекти. Целта на този шаблон за дизайн е да изолира създаването на обектите от тяхното използване.

Абстрактната фабрика капсулира група от методи Фабрика имащи близко предназначение. Клиентският код създава конкретна имплементация на абстрактната фабрика, след това използва основния интерфейс за да създава конкренти обекти. Клиентът не е задължен да знае коя от тези фабрики е създала конкретния обект, защото той използва само основния интерфейс към създадените обекти.

Този шаблон позволява замяната на конкретни класове, дори по време на изпълнение, без да е нужна промяна на кода, който ги използва. Това обаче е за сметка на допълнително усложняване на кода, което не е много желателно.

Примери редактиране

C++ редактиране

struct Button {
  virtual void paint() = 0;
};

struct WinButton : public Button {
  void paint (){
    std::cout << " I'm a window button \n";
  }
};

struct OSXButton : public Button {
  void paint (){
    std::cout << " I'm a OSX button \n";
  }
};

struct GUIFactory {
  virtual Button* createButton () = 0;
};

struct WinGUIFactory : public GUIFactory {
  Button* createButton (){
    return new WinButton();
  }
};

struct OSXGUIFactory : public GUIFactory {
  Button* createButton (){
    return new OSXButton();
  }
};

struct Application {
    Application(GUIFactory* factory){
        Button * button = factory->createButton();
        button->paint();
    }
};

/* application : */

int main()
{
  GUIFactory* factory1 = new WinGUIFactory();
  GUIFactory* factory2 = new OSXGUIFactory();

  Application* winApp  = new Application (factory1);
  Application* osxApp  = new Application (factory2);

  delete factory1, factory2;

  return 0;
}

C# редактиране

/*
 * GUIFactory example
 */

 abstract class GUIFactory {
     public static GUIFactory getFactory() {
         int sys = readFromConfigFile("OS_TYPE");
         if (sys==0) {
             return(new WinFactory());
         } else {
             return(new OSXFactory());
         }
    }
    public abstract Button createButton();
 }

 class WinFactory:GUIFactory {
     public override Button createButton() {
         return(new WinButton());
     }
 }

 class OSXFactory:GUIFactory {
     public override Button createButton() {
         return(new OSXButton());
     }
 }

 abstract class Button  {
     public string caption;
     public abstract void paint();
 }

 class WinButton:Button {
     public override void paint() {
        Console.WriteLine("I'm a WinButton: "+caption);
     }
 }

 class OSXButton:Button {
     public override void paint() {
        Console.WriteLine("I'm a OSXButton: "+caption);
     }
 }

 class Application {
     static void Main(string[] args) {
         GUIFactory aFactory = GUIFactory.getFactory();
         Button aButton = aFactory.createButton();
         aButton.caption = "Play";
         aButton.paint();
     }
     //output is
     //I'm a WinButton: Play
     //or
     //I'm a OSXButton: Play
 }

Java редактиране

 /*
 * GUIFactory example
 */

 public abstract class GUIFactory {
    public static GUIFactory getFactory() {
         int sys = readFromConfigFile("OS_TYPE");
         if (sys == 0) {
             return(new WinFactory());
         } else {
             return(new OSXFactory());
         }
    }
    public abstract Button createButton();
 }

 class WinFactory extends GUIFactory {
     public Button createButton() {
         return(new WinButton());
     }
 }

 class OSXFactory extends GUIFactory {
     public Button createButton() {
         return(new OSXButton());
     }
 }

 public abstract class Button  {
     private String caption;
     public abstract void paint();

     public String getCaption(){
         return caption;
     }
     public void setCaption(String caption){
         this.caption = caption;
     }
 }

 class WinButton extends Button {
     public void paint() {
        System.out.println("I'm a WinButton: "+ getCaption());
     }
 }

 class OSXButton extends Button {
     public void paint() {
        System.out.println("I'm a OSXButton: "+ getCaption());
     }
 }

 public class Application {
     public static void main(String[] args) {
         GUIFactory aFactory = GUIFactory.getFactory();
         Button aButton = aFactory.createButton();
         aButton.setCaption("Play");
         aButton.paint();
     }
     //output is
     //I'm a WinButton: Play
     //or
     //I'm a OSXButton: Play
 }
	public abstract class FinancialToolsFactory {
		public abstract TaxProcessor createTaxProcessor();
		public abstract ShipFeeProcessor createShipFeeProcessor();
	}

	public abstract class ShipFeeProcessor {
		abstract void calculateShipFee(Order order);
	}

	public abstract class TaxProcessor {
		abstract void calculateTaxes(Order order);
	}

        // Factories
	public class CanadaFinancialToolsFactory extends FinancialToolsFactory {
		public TaxProcessor createTaxProcessor() {
			return new CanadaTaxProcessor();
		}
		public ShipFeeProcessor createShipFeeProcessor() {
			return new CanadaShipFeeProcessor();
		}
	}

	public class EuropeFinancialToolsFactory extends FinancialToolsFactory {
		public TaxProcessor createTaxProcessor() {
			return new EuropeTaxProcessor();
		}
		public ShipFeeProcessor createShipFeeProcessor() {
			return new EuropeShipFeeProcessor();
		}
	}

	// Products
	public class EuropeShipFeeProcessor extends ShipFeeProcessor {
		public void calculateShipFee(Order order) {
		// insert here Europe specific ship fee calculation
		}
	}

	public class CanadaShipFeeProcessor extends ShipFeeProcessor {
		public void calculateShipFee(Order order) {
		// insert here Canada specific ship fee calculation
		}
	}

	public class EuropeTaxProcessor extends TaxProcessor {
		public void calculateTaxes(Order order) {
			// insert here Europe specific taxt calculation
		}
	}

	public class CanadaTaxProcessor extends TaxProcessor {
		public void calculateTaxes(Order order) {
			// insert here Canada specific taxt calculation
		}
	}

	// Client
	public class OrderProcessor {
		private TaxProcessor taxProcessor;
		private ShipFeeProcessor shipFeeProcessor;

		public OrderProcessor(FinancialToolsFactory factory) {
			taxProcessor = factory.createTaxProcessor();
			shipFeeProcessor = factory.createShipFeeProcessor();
		}
		public void processOrder (Order order)	{
			// ....
			taxProcessor.calculateTaxes(order);
			shipFeeProcessor.calculateShipFee(order);
			// ....
		}
	}

	// Integration with the overall application
	enum CountryCode {
        	EU,
 CA
    	}

	public class Application {
		public static void main(final String... args) {
			// .....
			final CountryCode countryCode = CountryCode.EU;

			final FinancialToolsFactory factory;
			switch (countryCode) {
            			case EU:
					factory = new EuropeFinancialToolsFactory();
 		break;
                		case CA:
					factory = new CanadaFinancialToolsFactory();
                    			break;
                		default:
                    			throw new IllegalStateException();
			}

			final OrderProcessor orderProcessor = new OrderProcessor(factory);
			orderProcessor.processOrder(new Order());
		}
	}

Perl редактиране

 # GUIFactory example on Perl

 package GUIFactory;

 sub getFactory($$) {
         shift; # skip class
         my $toolkit = shift;
         if ($toolkit eq 'GTK') {
             return(GtkFactory->new);
         } else {
             return(TkFactory->new);
         }
 }

 package GtkFactory;
 use base 'GUIFactory';

 sub new {
     bless({}, shift);
 }

 sub createButton {
         return(GtkButton->new);
 }

 package TkFactory;
 use base 'GUIFactory';

 sub new {
         bless({}, shift);
 }

 sub createButton() {
         return(TkButton->new);
 }

 package Button;

 sub new {
         $class = shift;
         my $self = {};
         $self{caption} = '';
         bless($self, $class);
         return $self;
 }

 package GtkButton;
 use base 'Button';

 sub paint() {
        print "I'm a GtkButton\n";
 }

 package TkButton;
 use base 'Button';

 sub paint() {
        print "I'm a TkButton\n";
 }

 package main;

 my $aFactory = GUIFactory->getFactory;
 my $aButton = $aFactory->createButton;
 $aButton->{caption} = "Play";
 $aButton->paint();

PHP редактиране

/*
 * Fabrique abstraite
 */
abstract class GUIFactory {
    public static function getFactory() {
        $sys = readFromConfigFile("OS_TYPE");
        if ($sys == 0) {
            return(new WinFactory());
        } else {
            return(new OSXFactory());
        }
    }
    public abstract function createButton();
}

class WinFactory extends GUIFactory {
    public function createButton() {
        return(new WinButton());
    }
}

class OSXFactory extends GUIFactory {
    public function createButton() {
        return(new OSXButton());
    }
}

abstract class Button {
    private $_caption;
    public abstract function render();

    public function getCaption(){
        return $this->_caption;
    }
    public function setCaption($caption){
        $this->_caption = $caption;
    }
}

class WinButton extends Button {
    public function render() {
        return "Je suis un WinButton: ".$this->getCaption();
    }
}

class OSXButton extends Button {
    public function render() {
        return "Je suis un OSXButton: ".$this->getCaption();
    }
}

$aFactory = GUIFactory::getFactory();
$aButton = $aFactory->createButton();
$aButton->setCaption("Démarrage");
echo $aButton->render();

//Le rendu est
//Je suis un WinButton: Démarrage
//ou
//Je suis un OSXButton: Démarrage

JavaScript редактиране

function WinButton() {
	this.paint = function() {
		document.write("I'm a window button.<br>");
	};
}

function OSXButton() {
	this.paint = function() {
		document.write("I'm a OSX button.<br>");
	};
}

function WinGUIFactory() {
	this.createButton = function() {
		return new WinButton();
	}
}

function OSXGUIFactory() {
	this.createButton = function() {
		return new OSXButton();
	}
}

function Application(factory) {
	var button = factory.createButton();
	button.paint();
}

var factory1 = new WinGUIFactory();
var factory2 = new OSXGUIFactory();

winApp = new Application(factory1);
osxApp = new Application(factory2);

delete winAPP, osxApp;

Eiffel редактиране

 --
 -- GUI Factory example
 --
 class GUI_FACTORY_FOR_CONFIG feature
    get_factory: GUI_FACTORY is
       once
          inspect read_from_config_file("OS_TYPE")
          when 0 then
             create {WIN_FACTORY} Result
          else
             create {OSX_FACTORY} Result
          end
       end
 end

 deferred class GUI_FACTORY feature
    create_button: BUTTON is deferred end
 end

 class WIN_FACTORY inherit GUI_FACTORY feature
    create_button: WIN_BUTTON is do create Result end
 end

 class OSX_FACTORY inherit GUI_FACTORY feature
    create_button: OSX_BUTTON is do create Result end
 end

 deferred class BUTTON feature
    caption: STRING
    set_caption(value: like caption) is do caption := value end
    paint is deferred end
 end

 class WIN_BUTTON inherit BUTTON feature
    paint is do print("I'm a WIN_BUTTON: "+caption+"%N") end
 end

 class OSX_BUTTON inherit BUTTON feature
    paint is do print("I'm a OSX_BUTTON: "+caption+"%N") end
 end

 class APPLICATION inherit GUI_FACTORY_FOR_CONFIG creation main feature
    main is local button : BUTTON do
       button := get_factory.create_button
       button.set_caption("Play")
       button.paint
    end
 end

Delphi редактиране

program AbstractFactory;

{$APPTYPE CONSOLE}

uses SysUtils;

type
  // AbstractProduct
  ICar = Class
  public
   function info: String; virtual; abstract;
  end;

// ConcreteProductA
  Ford = Class(ICar)
  public
   function info: String; override;
  end;

// ConcreteProductB
   Toyota  = Class(ICar)
  public
   function info: String; override;
  end;

// AbstractFactory
  CarFactory = Class
  public
   function CreateCar:ICar; virtual; abstract;
  end;

// ConcreteFactoryA
  FordFactory = Class(CarFactory)
  private
   function CreateCar:ICar; override;
  end;

// ConcreteFactoryB
  ToyotaFactory = Class(CarFactory)
  private
   function CreateCar:ICar; override;
  end;

{ Ford }
function Ford.info: String;
begin
 Result:='Ford';
end;

{ Toyota }
function Toyota.info: String;
begin
 Result:='Toyota';
end;

{ FordFactory }
function FordFactory.CreateCar: ICar;
begin
  Result:=Ford.Create;
end;

{ ToyotaFactory }
function ToyotaFactory.CreateCar: ICar;
begin
  Result:=Toyota.Create;
end;

var CF: CarFactory;
    C: ICar;
    i: Char;
begin
 writeln('Abstract factory');
 writeln('ToyotaFactory');
 Cf:= ToyotaFactory.Create;
 C:=CF.CreateCar;
 writeln(C.info);
 C.Free;
 Readln(i);

 writeln('FordFactory');
 Cf:= FordFactory.Create;
 C:=CF.CreateCar;
 writeln(C.info);
 C.Free;
 Readln(i);
end.