设计模式--Abstract Factory

一、概述
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态,工厂方法针对的仅仅是一种“产品”,或者称为“类”,而抽象工厂实际上针对很多平行的产品,因此层次不同。抽象工厂才是名副其实的“工厂”,即不仅仅只生产一种产品,抽象工厂是层次较高的模式,针对应用中需要使用的一系列相关的类给出一个创建接口。
 
学会了用抽象工厂模式,你将理解OOP的精华:面向接口编程。
 
二、意图
提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类。
 
三、Abstract Factory模式的结构:
设计模式--Abstract Factory
 
 
四、举例
学习抽像工厂模式时,个人觉得吕震宇老师的一个例子很能说明问题,如下所示:
设计模式--Abstract Factory// "AbstractFactory"
设计模式--Abstract Factory
abstract class AbstractFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    abstract public AbstractProductA CreateProductA();
设计模式--Abstract Factory    
abstract public AbstractProductB CreateProductB();
设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "ConcreteFactory1"
设计模式--Abstract Factory
class ConcreteFactory1 : AbstractFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    override public AbstractProductA CreateProductA()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new ProductA1();
设计模式--Abstract Factory    }

设计模式--Abstract Factory    
override public AbstractProductB CreateProductB()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new ProductB1();
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "ConcreteFactory2"
设计模式--Abstract Factory
class ConcreteFactory2 : AbstractFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    override public AbstractProductA CreateProductA()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new ProductA2();
设计模式--Abstract Factory    }

设计模式--Abstract Factory
设计模式--Abstract Factory    
override public AbstractProductB CreateProductB()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new ProductB2();
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "AbstractProductA"
设计模式--Abstract Factory
abstract class AbstractProductA
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "AbstractProductB"
设计模式--Abstract Factory
abstract class AbstractProductB
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    abstract public void Interact(AbstractProductA a);
设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "ProductA1"
设计模式--Abstract Factory
class ProductA1 : AbstractProductA
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "ProductB1"
设计模式--Abstract Factory
class ProductB1 : AbstractProductB
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    override public void Interact(AbstractProductA a)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        Console.WriteLine(
this + " interacts with " + a);
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "ProductA2"
设计模式--Abstract Factory
class ProductA2 : AbstractProductA
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "ProductB2"
设计模式--Abstract Factory
class ProductB2 : AbstractProductB
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    override public void Interact(AbstractProductA a)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        Console.WriteLine(
this + " interacts with " + a);
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory
// "Client" - the interaction environment of the products
设计模式--Abstract Factory
class Environment
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
// Fields
设计模式--Abstract Factory
    private AbstractProductA AbstractProductA;
设计模式--Abstract Factory    
private AbstractProductB AbstractProductB;
设计模式--Abstract Factory
设计模式--Abstract Factory    
// Constructors
设计模式--Abstract Factory
    public Environment(AbstractFactory factory)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        AbstractProductB 
= factory.CreateProductB();
设计模式--Abstract Factory        AbstractProductA 
= factory.CreateProductA();
设计模式--Abstract Factory    }

设计模式--Abstract Factory
设计模式--Abstract Factory    
// Methods
设计模式--Abstract Factory
    public void Run()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        AbstractProductB.Interact(AbstractProductA);
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory
设计模式--Abstract Factory设计模式--Abstract Factory
/**//// <summary>
设计模式--Abstract Factory
/// ClientApp test environment
设计模式--Abstract Factory
/// </summary>

设计模式--Abstract Factoryclass ClientApp
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
static void Main(string[] args)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        AbstractFactory factory1 
= new ConcreteFactory1();
设计模式--Abstract Factory        Environment e1 
= new Environment(factory1);
设计模式--Abstract Factory        e1.Run();
设计模式--Abstract Factory
设计模式--Abstract Factory        AbstractFactory factory2 
= new ConcreteFactory2();
设计模式--Abstract Factory        Environment e2 
= new Environment(factory2);
设计模式--Abstract Factory        e2.Run();
设计模式--Abstract Factory        Console.ReadLine();
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

 
五、优点
1、分离了具体的类。抽象工厂模式帮助你控制一个应用创建的对象的类,因为一个工厂封装创建产品对象的责任和过程。它将客户和类的实现分离,客户通过他们的抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,它们不出现在客户代码中;
2、使产品系列容易交换,只要更换相应的具体工厂即可(经常用工厂方法来实现);
3、有利于产品的一致性,由抽象工厂创建的产品必须符合相同的接口,任何在子类中的特殊功能都不能体现在统一的接口中;
 
六、缺点
1、难以支持新产品的类型,如果抽象工厂的基类要发生变化,那么针对每个产品系列的具体工厂也都要发生变化,显然这是很麻烦的;
2、不能创建有着不同个数对象的系列;
注:
抽象工厂模式主要在于应对“新系列”的需求变化。其缺点在于难于应付“新对象”的需求变动。如果在开发中出现了新对象,该如何去解决呢?这个问题并没有一个好的答案,下面我们看一下李建忠老师的回答:
“GOF《设计模式》中提出过一种解决方法,即给创建对象的操作增加参数,但这种做法并不能令人满意。事实上,对于新系列加新对象,就我所知,目前还没有完美的做法,只有一些演化的思路,这种变化实在是太剧烈了,因为系统对于新的对象是完全陌生的。”
 
七、适用性
分析了上面的优缺点,当我们在遇到如下情况时,应当考虑使用抽象工厂模式:
1、一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的;
2、这个系统有多于一个的产品组合,而系统只需要使用其中某一产品组合;
3、同属于同一个产品组合的产品是在一起使用的,这一约束必须在系统的设计中体现出来;
4、系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现;
 
八、实现要点
1、抽象工厂将产品对象的创建延迟到它的具体工厂的子类。
2、如果没有应对“多系列对象创建”的需求变化,则没有必要使用抽象工厂模式,这时候使用简单的静态工厂完全可以。
3、系列对象指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
4、抽象工厂模式经常和工厂方法模式共同组合来应对“对象创建”的需求变化。
5、通常在运行时刻创建一个具体工厂类的实例,这一具体工厂的创建具有特定实现的产品对象,为创建不同的产品对象,客户应使用不同的具体工厂。
6、把工厂作为单件,一个应用中一般每个产品系列只需一个具体工厂的实例,因此,工厂通常最好实现为一个单件模式。
7、创建产品,抽象工厂仅声明一个创建产品的接口,真正创建产品是由具体产品类创建的,最通常的一个办法是为每一个产品定义一个工厂方法,一个具体的工厂将为每个产品重定义该工厂方法以指定产品,虽然这样的实现很简单,但它确要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。

九、应用场景
1、应用程序开发中需要支持多数据库,比如支持Oracle、SqlServer等;
设计模式--Abstract Factorypublic class DBOperator
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
private DBFactory dbf;
设计模式--Abstract Factory    
private IDbConnection dbconn;
设计模式--Abstract Factory    
public DBOperator(DBFactory dbf)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
this.dbf = dbf;
设计模式--Abstract Factory    }

设计模式--Abstract Factory 
设计模式--Abstract Factory    
public void Open(string connstring)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        dbconn 
= dbf.GetDBConnection();
设计模式--Abstract Factory        dbconn.ConnectionString 
= connstring;
设计模式--Abstract Factory        dbconn.Open();
设计模式--Abstract Factory    }

设计模式--Abstract Factory 
设计模式--Abstract Factory    
public DataSet ExecSQL(string sql)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        IDbCommand dbc 
= dbf.GetDBCommand();
设计模式--Abstract Factory        dbc.CommandText 
= sql;
设计模式--Abstract Factory        dbc.CommandType 
= CommandType.Text;
设计模式--Abstract Factory        dbc.Connection 
= dbconn;
设计模式--Abstract Factory        IDataAdapter ida 
= dbf.GetDBDataAdapter(dbc);
设计模式--Abstract Factory        DataSet ds 
= null;
设计模式--Abstract Factory        ida.Fill(ds);
设计模式--Abstract Factory        
return ds;
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory
public abstract class DBFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
public abstract IDbCommand GetDBCommand();
设计模式--Abstract Factory    
public abstract IDbConnection GetDBConnection();
设计模式--Abstract Factory    
public abstract IDataAdapter GetDBDataAdapter(IDbCommand idc);
设计模式--Abstract Factory}

设计模式--Abstract Factory 
设计模式--Abstract Factory
public class SQLDBFactory : DBFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
public SQLDBFactory()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{ }
设计模式--Abstract Factory    
public override IDbCommand GetDBCommand()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new SqlCommand();
设计模式--Abstract Factory    }

设计模式--Abstract Factory    
public override IDbConnection GetDBConnection()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new SqlConnection();
设计模式--Abstract Factory    }

设计模式--Abstract Factory    
public override IDataAdapter GetDBDataAdapter(IDbCommand idc)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
return new SqlDataAdapter((SqlCommand)idc);
设计模式--Abstract Factory    }

设计模式--Abstract Factory}
 
设计模式--Abstract Factory
public class OracleDBFactory : DBFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
//因只是表达意思,此处没有实现
设计模式--Abstract Factory
}

设计模式--Abstract Factory
public class OleDBFactory : DBFactory
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
//因只是表达意思,此处没有实现
设计模式--Abstract Factory
}

设计模式--Abstract Factory 
设计模式--Abstract Factory
//Client
设计模式--Abstract Factory
public class DBUse
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    DBFactory dbf 
= null;
设计模式--Abstract Factory    
public DBUse(string dbType)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
switch (dbType.ToLower())
设计模式--Abstract Factory设计模式--Abstract Factory        
设计模式--Abstract Factory{
设计模式--Abstract Factory            
case "sql":
设计模式--Abstract Factory                dbf 
= new SQLDBFactory();
设计模式--Abstract Factory                
break;
设计模式--Abstract Factory            
case "oracle":
设计模式--Abstract Factory                dbf 
= new OracleDBFactory();
设计模式--Abstract Factory                
break;
设计模式--Abstract Factory            
default:
设计模式--Abstract Factory                dbf 
= new OleDBFactory();
设计模式--Abstract Factory                
break;
设计模式--Abstract Factory        }

设计模式--Abstract Factory    }

设计模式--Abstract Factory 
设计模式--Abstract Factory    
public DataSet GetDataSet(string sql)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        DBOperator dbop 
= new DBOperator(dbf);
设计模式--Abstract Factory        dbop.Open(
"connctionstring");
设计模式--Abstract Factory        
return dbop.ExecSQL(sql);
设计模式--Abstract Factory    }

设计模式--Abstract Factory}
 
设计模式--Abstract Factory
class Program
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
static void Main(string[] args)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory      
//客户程式调用
设计模式--Abstract Factory
    }

设计模式--Abstract Factory}
 
 
2、开发电脑组装软件时,比如要组装不同品牌的PC;
针对电脑组装,我们再来看一下上面的例子,我们可以做如下假设:
1)一台电脑的组成就是主板和CPU
2)ConcreteFactory1对应于方正公司,ConcreteFactory2对应于联想公司
3)AbstractProductA对应于主板,AbstractProductB对应于CPU
4)可以把Environment想像成一个第三方公司的组装工艺,此公司从方正和联想采购主板和CPU进行组装
然后客户程式(第三方公司具体组装电脑)在使用时,理解如下:
设计模式--Abstract Factoryclass ClientApp
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory  
//如下两个Run(),在实际使用时,一般只会使用其中一个
设计模式--Abstract Factory
  public static void Main(string[] args)
设计模式--Abstract Factory设计模式--Abstract Factory  
设计模式--Abstract Factory{
设计模式--Abstract Factory    
//获得方正公司的产品,注意此处客户程式并不知道有哪些具体产品
设计模式--Abstract Factory
    AbstractFactory factory1 = new ConcreteFactory1();
设计模式--Abstract Factory    
//按照组装工艺进行组装,就得到方正品牌PC
设计模式--Abstract Factory
    Environment e1 = new Environment( factory1 );
设计模式--Abstract Factory    e1.Run();
设计模式--Abstract Factory  
//获得联想公司的产品
设计模式--Abstract Factory
    AbstractFactory factory2 = new ConcreteFactory2();
设计模式--Abstract Factory  
//按照组装工艺进行组装,就得到联想品牌PC
设计模式--Abstract Factory
    Environment e2 = new Environment( factory2 );
设计模式--Abstract Factory    e2.Run();
设计模式--Abstract Factory  }

设计模式--Abstract Factory}
 
此时,有心的读者可能已经发现,在客户程式中,不还是要和具体的类有耦合(AbstractFactory factory1 = new ConcreteFactory1();
)吗?我们可以有两种方式来解决,第一是把这种修改放到配置文件中,实现运行时的维护,如下:
设计模式--Abstract Factory<?xml version="1.0" encoding="utf-8" ?>
设计模式--Abstract Factory
设计模式--Abstract Factory
<configuration>
设计模式--Abstract Factory
设计模式--Abstract Factory         
<appSettings>
设计模式--Abstract Factory
设计模式--Abstract Factory              
<add key="factoryName" value="ModernFacilitiesFactory"></add>
设计模式--Abstract Factory
设计模式--Abstract Factory         
</appSettings>
设计模式--Abstract Factory
设计模式--Abstract Factory
</configuration>
设计模式--Abstract Factory

 

然后客户程式在调用时:
设计模式--Abstract Factory设计模式--Abstract Factory/**//// <summary>
设计模式--Abstract Factory
/// ClientApp test environment
设计模式--Abstract Factory
/// </summary>

设计模式--Abstract Factoryclass Program
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
public static AbstractFactory GetInstance()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
string factoryName = ConfigurationSettings.AppSettings["factoryName"];
设计模式--Abstract Factory        AbstractFactory f;
设计模式--Abstract Factory        
switch (factoryName)
设计模式--Abstract Factory设计模式--Abstract Factory        
设计模式--Abstract Factory{
设计模式--Abstract Factory            
case "ConcreteFactory1":
设计模式--Abstract Factory                f 
= new ConcreteFactory1();
设计模式--Abstract Factory                
break;
设计模式--Abstract Factory            
case "ConcreteFactory2":
设计模式--Abstract Factory                f 
= new ConcreteFactory2();
设计模式--Abstract Factory                
break;
设计模式--Abstract Factory            
default:
设计模式--Abstract Factory                f 
= null;
设计模式--Abstract Factory                
break;
设计模式--Abstract Factory        }

设计模式--Abstract Factory        
return f;
设计模式--Abstract Factory    }

设计模式--Abstract Factory    
static void Main(string[] args)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
//此处就已经和ConcreteFactory解耦
设计模式--Abstract Factory
        AbstractFactory factory1 = GetInstance();
设计模式--Abstract Factory        Environment e1 
= new Environment(factory1);
设计模式--Abstract Factory        e1.Run();
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

设计模式--Abstract Factory

这样如果用户哪一天需要组装一台联想电脑,只要把配置文件中的factoryName改为ConcreteFactory2即可,程式不需要做任何修改。这种方式适用在系列对象不发生系列增加的情况下。
 
第二就是利用一个反射的机制来实现,此种方式可以扩展新的系列对象,我们就可以通过添加DLL并配合配置文件的使用,就能在不修改源程序代码的情况下,扩展出我们需要的新的系列对象。如下:
设计模式--Abstract Factory设计模式--Abstract Factory/**//// <summary>
设计模式--Abstract Factory
/// ClientApp test environment
设计模式--Abstract Factory
/// </summary>

设计模式--Abstract Factoryclass Program
设计模式--Abstract Factory设计模式--Abstract Factory
设计模式--Abstract Factory{
设计模式--Abstract Factory    
public static AbstractFactory GetInstance()
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
string factoryName = ConfigurationSettings.AppSettings["factoryName"];
设计模式--Abstract Factory        AbstractFactory f;
设计模式--Abstract Factory        
if (factoryName != "")
设计模式--Abstract Factory            f 
= (AbstractFactory)Assembly.Load(factoryName).CreateInstance(factoryName);
设计模式--Abstract Factory        
else
设计模式--Abstract Factory            f 
= null;
设计模式--Abstract Factory        
return f;
设计模式--Abstract Factory    }

设计模式--Abstract Factory    
static void Main(string[] args)
设计模式--Abstract Factory设计模式--Abstract Factory    
设计模式--Abstract Factory{
设计模式--Abstract Factory        
//此处就已经和ConcreteFactory解耦
设计模式--Abstract Factory
        AbstractFactory factory1 = GetInstance();
设计模式--Abstract Factory        Environment e1 
= new Environment(factory1);
设计模式--Abstract Factory        e1.Run();
设计模式--Abstract Factory    }

设计模式--Abstract Factory}

这样,我们在扩展时仅需将扩展的DLL放在相应的路径下并配合配置文件即实现了我们的扩展。
 
十、总结
总之,抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,运用抽象工厂模式的关键点在于应对“多系列对象创建”的需求变化。一句话,学会了抽象工厂模式,你将理解OOP的精华:面向接口编程。
 
以上仅是学习时的个人理解,不对之处请指正,谢谢!

转载于:https://www.cnblogs.com/xiongeee/archive/2007/03/09/669773.html