我有一个程序,它引用了一个外部DLL:
magic.externalFunctions.sql.dll
取决于目标系统,我可能需要以下内容:
magic.externalFunctions.nosql.dll
这些DLL是提供相同功能的外部库。即使是公共方法和属性也是一样的。但是他们不具有组合的接口或基类。
现在我需要根据目标系统在这两个库之间进行选择。如果他们拥有一个共同的接口,我会做类似的事情:
public class DoDatabaseStuff() {
private IMagic _magic
public DoDatabaseStuff(bool useNoSql) {
if (useNoSql) {
_magic=new SqlMagic();
} else {
_magic=new NoSqlMagic();
}
myTable=_magic.Table.Create("CustomerTable");
myTable.Columns.Add(typeof(int),"ID");
myTable.Columns.Add(typeof(string),"Name");
}
}
有没有办法在不使用过量反射的情况下解决这个问题?我仍然希望使用类似myTable.Columns.Add()
而不是tableType.GetMethod("Add").Invoke()...
我也不想使用不同的构建配置在csproj中使用条件。虽然这在理论上确实有效,但每次csproj自动更改时都会被破坏(例如,nuget-package更新)
答案 0 :(得分:5)
如果您遇到了无法改变的糟糕设计,那么最好的方法就是将该设计从代码中删除。在这种情况下,这意味着您应该创建外部程序集缺少的公共接口。
您可以使用适配器提供统一的界面,以避免初始设计缺陷超出代码核心。
首先要为要访问的原始类创建抽象:
public interface IMagic {
ITable CreateTable(string name);
}
public interface ITable {
void AddColumn(Type type, string name);
}
然后你提供适配器:
class SqlMagicAdapter : IMagic {
SqlMagic m_innerMagic = new SqlMagic();
ITable CreateTable(string name) {
return new SqlTableAdapter(m_innerMagic.Table.Create(name));
}
}
class SqlTableAdapter : ITable {
SqlTable m_innerTable;
public SqlTableAdapter(SqlTable innerTable) {
m_innerTable = innerTable;
}
void AddColumn(Type type, string name) {
m_innerTable.Columns.Add(type, name);
}
}
class NoSqlMagicAdapter : IMagic {
NoSqlMagic m_innerMagic = new NoSqlMagic();
ITable CreateTable(string name) {
return new NoSqlTableAdapter(m_innerMagic.Table.Create(name));
}
}
class NoSqlTableAdapter : ITable {
NoSqlTable m_innerTable;
public NoSqlTableAdapter(NoSqlTable innerTable) {
m_innerTable = innerTable;
}
void AddColumn(Type type, string name) {
m_innerTable.Columns.Add(type, name);
}
使用工厂方法,您可以返回相应的适配器:
public static class MagicFactory {
public static IMagic GetMagic(bool useNoSql) {
if (useNoSql) {
return new NoSqlMagic();
}
else {
return new SqlMagic();
}
}
}
只使用工厂返回的抽象,您的核心代码可以保持清洁:
public class DoDatabaseStuff() {
private IMagic _magic
public DoDatabaseStuff(bool useNoSql) {
_magic = MagicFactory.GetMagic(useNoSql);
ITable myTable = _magic.CreateTable("CustomerTable");
myTable.AddColumn(typeof(int), "ID");
myTable.AddColumn(typeof(string), "Name");
}
}
另一个优势是您还可以为将来的任何更改做好准备,例如,另一个更新的外部库与之前的更新不兼容。您可以轻松支持这些新功能,而无需更改核心代码。