工厂组+反射技术+局部类 结合运用
因为单纯简单工厂,工厂方法,抽象工厂都有自己的不足点。
缺点--
简单工厂:当要增加具体产品类(如:Product_C)是都要修改SimpleFactory类,有点违背了开放封闭原则--对扩展开放,修改封闭。而简单工厂的致命弱点是不能增加产品系列(如:IProductX)等。所以简单工厂只试用于单个系列的产品(就一个IProduct)
工厂方法:相对于简单工厂,工厂方法暴露给用户的类相对增加了,有IFactory和一系列的具体工厂类,还有IProduct类。但是增加其他系列的产品时(如:IProductX),工厂方法并没有解决问题。
抽象工厂:而抽象工厂实际上并没有解决增加其他系列产品的问题。它只是在一开始写死了几个产品系列。可以说它就是变相的工厂方法。
现在就让我们一点点来解决这些问题吧。使它真正的符合‘开放-封闭’原则。
我们先来熟悉一下C#的局部类:http://baike.baidu.com/view/2308848.htm
通过它我们可以把我们的工厂类改建:
原:
抽象工厂里的工厂类接口:
public interface IFactory { IProduct1 factory1(); IProduct2 factory2(); }
现:
改建后的抽象工厂类(版本1):
public class Factory { private string str_style=""; public Factory() { str_style = ConfigurationSettings.AppSettings["style"].ToString(); } public IProduct1 factory1() { var product = Assembly.Load("Design Mode").CreateInstance("Design_Mode.Factories." + "Product_" + str_style + "1") as IProduct1; return product; } public IProduct2 factory2() { var product = Assembly.Load("Design Mode").CreateInstance("Design_Mode.Factories." + "Product_" + str_style + "2") as IProduct2; return product; } }
最后是通过局部类来改建后的抽象工厂类(版本2):
首先我们要建三个类,如图:
Factory类的代码(这个局部类的内容是一些初始化属性和构造函数):
partial class Factory { private string str_style=""; public Factory() { str_style = ConfigurationSettings.AppSettings["style"].ToString(); } }
Factory1类的代码(一个factory1的内容定义):
partial class Factory { public IProduct1 factory1() { var product = Assembly.Load("Design Mode").CreateInstance("Design_Mode.Factories." + "Product_" + str_style + "1") as IProduct1; return product; } }
Factory2类的代码(一个factory2的内容定义):
partial class Factory { public IProduct2 factory2() { var product = Assembly.Load("Design Mode").CreateInstance("Design_Mode.Factories." + "Product_" + str_style + "2") as IProduct2; return product; } }
我这么写是为了当要动态增加产品系列的时候不需要去修改原来的代码。只要新增一个局部工厂类,增加一个factory方法。把那个系列的产品增加上去就OK了。这样就完全符合‘开放-封闭’原则了。
这样就解决了动态增加系列产品的问题。现在我们就完全实现了动态增加系列产品和动态增加具体产品的问题。这样是不是就没有什么需要改进的地方了呢?其实还是有的,如果我要在系统运行的时候切换具体产品呢?这个应该怎么做呢?
我们可以通过另一个技术:反射来实现。
首先我们应该先了解一下反射(可以网上找找相关资料):反射就是可以通过字符串来动态创建类。
var product = Assembly.Load("类所在的组件名").CreateInstance("类名") as IProduct1;
而我是通过在App.config中读取一些参数来初始化要反射创建的类:
str_style = ConfigurationSettings.AppSettings["style"].ToString();
好了。这样我们就完全灵活实现了。
全部代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Configuration;
namespace Design_Mode.Factories
{
partial class Factory
{
private string str_style="";
public Factory()
{
str_style = ConfigurationSettings.AppSettings["style"].ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Configuration;
namespace Design_Mode.Factories
{
partial class Factory
{
public IProduct1 factory1()
{
var product = Assembly.Load("Design Mode").CreateInstance("Design_Mode.Factories." + "Product_" + str_style + "1") as IProduct1;
return product;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Configuration;
namespace Design_Mode.Factories
{
partial class Factory
{
public IProduct2 factory2()
{
var product = Assembly.Load("Design Mode").CreateInstance("Design_Mode.Factories." + "Product_" + str_style + "2") as IProduct2;
return product;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Design_Mode.Factories
{
public interface IProduct1
{
void operation();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Design_Mode.Factories
{
public interface IProduct2
{
void operation();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Design_Mode.Factories
{
class Product_A1 : IProduct1
{
#region IProduct1 成员
public void operation()
{
Console.Write("Product_A1\n");
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Design_Mode.Factories
{
class Product_A2 :IProduct2
{
#region IProduct2 成员
public void operation()
{
Console.Write("Product_A2\n");
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Design_Mode.Factories
{
class Product_B1 : IProduct1
{
#region IProduct1 成员
public void operation()
{
Console.Write("Product_B1\n");
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Design_Mode.Factories
{
class Product_B2 : IProduct2
{
#region IProduct2 成员
public void operation()
{
Console.Write("Product_B2\n");
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Design_Mode.Factories;
namespace Design_Mode
{
class Program
{
static void Main(string[] args)
{
#region 工厂组应用
Factory factory = new Factory();
IProduct1 product = factory.factory1();
if (product != null)
product.operation();
#endregion
}
}
}
App.config代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="style" value="B"/>
</appSettings>
</configuration>
上述就是简单的时候。通过上面简单的实现。我们可以构建动态切换数据库的功能。如A类的是SQL SERVER,B类的是Access等,当要切换的时候就可以通过App.config文件里面修改下数据库,并把数据库连接修改一下就可以了。这样就方便多了。