享元可以理解为共享元素,提倡的是一种资源共享的理念,以此来减少资源占用空间的情况。根据对象的共有特性进行区分并存放到容器中,从容器中取出对象访问。主要通过key-value的机制来存取对象,当key不存在时则创建一个对象,并存放入基于key-value机制的容器,然后取出使用;如果key已存在,则直接取出使用。
此文以数据库对象为例,并非真实情景,仅作示例进行说明。
假如,系统中有业务、产品、客户管理,业务库按业务性质区分有多个数据库、产品库按分类区分有多个数据库、客户库按地区有多个数据库。
访问业务库数据库时,要用业务库的数据库对象进行访问;访问产品数据库时,要用产品库的数据库对象进行访问;同时访问客户数据库时,要用客户库的数据库对象进行访问。于是就有了三种数据库访问对象,分别是业务库数据库对象(DBB)、产品库数据库对象(DBP)、客户库数据库对象(DBC)。分三类数据库对象是由连接串的生成规则所决定,这就是各自的不同的地方,属于不享元的部分。
这些数据库对象由享元工厂进行管理,当我从享元工厂用关键"DBB"取数据库对象时,享元工厂会先检查key:"DBB"是否已存在,当没找到这个key时,就会先创建一个数据库对象存放入容器中,然后返回这个对象的实例;如果找到这个key,就直接返回这个对象的实例。
一般key-value的容器可以使用Hashtable、Dictionary<string, object>,或自己写一个。
DB:接口,声明了GetConnection方法,通过这个方法获取数据库对象实例;
DBB类、DBP类、DBC类:分别实现DB接口的GetConnection方法,各自的实现中根据不同的关键字生成不同的数据库连接串,并返回数据库对象实例;
DBFactory类:享元工厂,dict是一个Dictionary<string, DB>类型的容器,通过dict对象来存放继承DB接口的对象实例,并在GetDB方法中判断指定key是存在,不存在则先创建对象放入容器中,然后返回对象;已存在则直接返回对象。
public interface DB { SqlConnection GetConnection(string kw); } public class DBB : DB { public DBB() { } public SqlConnection GetConnection(string kw) { return new SqlConnection($"Server=.;Database=DBB_{kw}_B;uid=;pwd=;"); } } public class DBP : DB { public DBP() { } public SqlConnection GetConnection(string kw) { return new SqlConnection($"Server=.;Database=DBP_{kw}_P;uid=;pwd=;"); } } public class DBC : DB { public DBC() { } public SqlConnection GetConnection(string kw) { return new SqlConnection($"Server=.;Database=DBC_{kw}_C;uid=;pwd=;"); } } public class DBFactory { private Dictionary<string, DB> dict; public DBFactory() { dict = new Dictionary<string, DB>(); } public DB GetDB(string key) { if (!dict.ContainsKey(key)) { if (key.Equals("DBB")) dict.Add(key, new DBB()); else if (key.Equals("DBP")) dict.Add(key, new DBP()); else dict.Add(key, new DBC()); } return dict[key]; } }