Создание объекта интерфейса и инкапсуляция n-уровня
Мы создаем систему, в которой мы хотим, чтобы конечная реализация "скрывала" слой доступа к данным (чтобы мы могли изменить его в будущем).
Таким образом, идея заключается в том, что код приложения будет вызывать интерфейс, который будет реализован объектами доступа к базе данных. Итак, у нас есть класс интерфейса:
public interface DatabaseInterface
{
void Create(DataObject obj);
}
Тогда у нас есть класс, который реализует интерфейс:
public class DatabaseAccess : DatabaseInterface
{
void Create(DataObject obj)
{
Entity dbContext = new Entity();
dbContext.Data.Add (obj);
dbContext.SaveChanged();
}
}
Вместе все это, у нас есть класс DataObject:
public class DataObject
{
integer Data1;
string Data2;
}
Наши проблемы лежат в основном приложении, так как я не знаю, что такое реализация DatabaseInterface:
public class CreateElementOnDatabase
{
DataObject myObj = new DataObject();
myObj.Data1 = 10;
myObj.Data2 = "Test String";
var dbAccess = new DatabaseInterface() <=== I know this is not possible, but don´t know what to do!!!!
dbAccess.Create (myObj);
}
Как мне вызвать реализованный метод, не зная, какой класс это сделал? Конечно, я что-то упустил в своем дизайне.
Мы ДЕЙСТВИТЕЛЬНО хотим сделать приложение полностью независимым от кода ниже.
[РЕДАКТИРОВАТЬ 1]
Эти реализации находятся в разных библиотеках классов. Итак, у меня есть следующее: Проект приложения DatabaseInterface проект DatabaseAccess проект DataObject проект
2 ответа
Вам не хватает "фабричного" класса, который создает экземпляры для внешнего мира на основе параметров или настроек конфигурации, которые он получает (если они хотят, чтобы внешний мир влиял на его поведение), или принимает свои собственные решения, то есть они будут создавать экземпляры либо введите A или B, основываясь на их внутренней логике, которую нельзя изменить извне. В приведенном ниже коде вы увидите DatabaseFactory, который вы упустили. Также обратите внимание на приватные / публичные / внутренние модификаторы, которые важны для того, чтобы убедиться, что вы раскрываете то, что нужно, а не больше, чем вам нужно (общедоступность всех классов создает путаницу для тех, кто хочет использовать вашу библиотеку)
Вот код
// interfaces must be public - this is the "contract" with the outside world / assemblies
public interface IDatabase
{
void Create(DataObject obj);
}
// classes that implement interfaces should be internal - outside world don't know about them
internal class SQLDatabase : IDatabase
{
// internal on constructor helps you to make sure you are the only one
// that can create such an instance
internal SQLDatabase()
{
}
void Create(DataObject obj)
{
Entity dbContext = new Entity();
dbContext.Data.Add(obj);
dbContext.SaveChanged();
}
}
internal class OracleDatabase : IDatabase
{
internal OracleDatabase()
{
}
void Create(DataObject obj)
{
//oracle creation method
}
}
public class DataObject
{
int Data1;
string Data2;
}
// this is the factory class that creates the instances for you (ourside world)
public class DatabaseFactory
{
// you can use either params or ideally app.config keys
public IDatabase CreateInstace()
{
if (ConfigSetting == "SQL")
{
return new SQLDatabase();
}
else if (ConfigSetting == "Oracle")
{
return new OracleDatabase();
}
else throw new System.Exception ("invalid configuration setting key");
}
}
// this is in external assembly:
public class CreateElementOnDatabase
{
DataObject myObj = new DataObject();
myObj.Data1 = 10;
myObj.Data2 = "Test String";
// you only work with public interfaces
// and the factory creates the instances for you ...
IDatabase db = DatabaseFactory.CreateInstace();
db.Create(myObj);
}
Вы можете создать класс, который будет создавать правильный объект DAL. Что-то вроде этого:
public class RepositoryFactory {
public static DatabaseInterface MakeDAL() {
return new DatabaseAccess();
}
}
Затем, чтобы сделать объект DAL:
var dbAccess = RepositoryFactory.MakeDAL();
В зависимости от того, сколько вы хотите разделить между приложением и доступом к базе данных, вы бы поместили интерфейсы, реализации интерфейса и фабричный класс в отдельные сборки или поместили некоторые в одну сборку, а некоторые в другую. Это действительно зависит от того, что вы имеете в виду, когда говорите "полностью независимы от исходного кода".