天天看點

淺談 java 設計模式--抽象工廠模式(AbstractFactory pattern)

問題:

        當系統要建立一組相關或者互相依賴的對象時, 請使用抽象工廠模式.

        抽象工廠模式可以向用戶端提供一個接口, 使得用戶端可以在不必指定産品的具體類型的情況下, 建立多個産品族中的産品對象. 這就是抽象工廠的用意.

類圖:

淺談 java 設計模式--抽象工廠模式(AbstractFactory pattern)

源代碼:

package com.designpatterns.AbstractFactory;
/**
 * 抽象工廠
 */
public interface AbstractFactory {
     public AbstractProductA createProductA();
     public AbstractProductB createProductB();
}

public interface AbstractProductA {
     public void operation();
}

public interface AbstractProductB {
     public void operation();
}

public class ConcreteFactory1 implements AbstractFactory{
   public AbstractProductA createProductA(){
      return new ProductA1();
   }
 
   public AbstractProductB createProductB(){
       return new ProductB1();
   }
}

public class ConcreteFactory2 implements AbstractFactory{ 
    public AbstractProductA createProductA(){
        return new ProductA2();
    }
 
    public AbstractProductB createProductB(){
        return new ProductB2();
    }
}

public class ProductA1 implements AbstractProductA {
   public ProductA1(){
      System.out.println("ProductA1...");
   }
 
   public void operation() {} 
}

public class ProductA2 implements AbstractProductA {
   public ProductA2(){
      System.out.println("ProductA2...");
   }
 
   public void operation() {} 
}

public class ProductB1 implements AbstractProductB {
    public ProductB1(){
       System.out.println("ProductB1...");
    }
 
    public void operation() {} 
}

public class ProductB2 implements AbstractProductB {
    public ProductB2(){
       System.out.println("ProductB2...");
    }
    public void operation() {} 
}

/**
 * 用戶端類
 */
public class Client {
    public static void main(String[] args) {
        AbstractFactory af1 = new ConcreteFactory1();
        af1.createProductA();
        af1.createProductB();

        AbstractFactory af2 = new ConcreteFactory2();
        af2.createProductA();
        af2.createProductB();
    } 
}
           

讨論:

    AbstractFactory模式是為建立一組(有多類)相關或依賴的對象提供建立接口, 而Factory模式是為一類對象提供建立接口或延遲對象的建立到子類中實作. AbstractFactory模式通常都是使用Factory模式實作, 如上例所示.

Definition

Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Class Diagram

淺談 java 設計模式--抽象工廠模式(AbstractFactory pattern)

Participants

  • Abstract Factory (FinancialToolsFactory)
    • declares an interface for operations that create abstract products objects
  • Concrete Factory (EuropeFinancialToolsFactory, CanadaFinancialToolsFactory)
    • implements the operations to create concrete product objects
  • Abstract Product (TaxProcessor, ShipFeeProcessor)
    • declares an interface for a type of product object
  • Concrete Product (EuropeTaxProcessor, CanadaTaxProcessor, EuropeShipFeeProcessor, CanadaShipFeeProcessor)
    • defines a product object to be created by the corresponding concrete factory implements the AbstractProduct interface
  • Client (OrderProcessor)
    • uses interfaces declared by AbstractFactory and AbstractProduct classes

Example: Financial Tools Factory

Example: Class Diagram

淺談 java 設計模式--抽象工廠模式(AbstractFactory pattern)

Example: Java sample code

// Factories
	package com.apwebco.patterns.gof.abstractfactory;
	public abstract class FinancialToolsFactory {
		public abstract TaxProcessor createTaxProcessor();
		public abstract ShipFeeProcessor createShipFeeProcessor();
	}
	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 abstract class ShipFeeProcessor {
		abstract void calculateShipFee(Order order);
	}
	public abstract class TaxProcessor {
		abstract void calculateTaxes(Order order);
	}
	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
	public class Application {
		public static void main(String[] args) {
			// .....
			String countryCode = "EU";
			Customer customer = new Customer();
			Order order = new Order();
			OrderProcessor orderProcessor = null;
			FinancialToolsFactory factory = null;
	
			if (countryCode == "EU") {
				factory = new EuropeFinancialToolsFactory();
			} else if (countryCode == "CA") {
				factory = new CanadaFinancialToolsFactory();
			}
			orderProcessor = new OrderProcessor(factory);
			orderProcessor.processOrder(order);
		}
	}
    	      

Benefits

  • Isolates concrete classes
  • Allows to change product family easily
  • Promotes consistency among products

Usage

  • When the system needs to be independent of how its products are created composed and represented.
  • When the system needs to be configured with one of multiple families of products.
  • When a family of products need to be used together and this constraint needs to be enforced.
  • When you need to provide a library of products, expose their interfaces not the implementation.