Я создаю приложение для отслеживания активов. Использование SQL Server 2008, C# .NET и Entity Framework. Это мой первый опыт создания репозитория, который, согласно моим исследованиям, предназначен для абстрагирования процесса доступа к данным. Я экспериментировал с несколькими дизайнами, и мне любопытно, хороши ли какие-либо из них или представляют ли какие-либо серьезные риски для разработки. Репозиторий должен поддерживать запросы активов по серийному номеру, штрих-коду или имени хоста.
Чтобы примеры были короткими, я не включаю методы обновления, удаления и вставки. Кроме того, в примерах игнорируются возможные универсальные реализации, так как универсальную реализацию всегда можно разработать позже, а прямо сейчас она только сделает примеры более запутанными. Пожалуйста, прочитайте следующие 3 дизайна и дайте мне знать, если я на правильном пути с любым из них:
Дизайн 1
Моя первая конструкция выглядела так:
public interface IAssetRepository
{
public Asset fetchBySerialNumber(String serialNumber);
public Asset fetchByBarcode(String barcode);
public ICollection<Asset> fetchByHostname(String hostname);
public Asset fetchActiveByHostname(String hostname);
}
public class AssetRepository : IAssetRepository
{
private InventoryEntites entities;
public Asset fetchBySerialNumber(String serialNumber)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.SerialNumber == serialNumber
select a;
return query.FirstOrDefault();
}
public Asset fetchByBarcode(String barcode)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Barcode == barcode
select a;
return query.FirstOrDefault();
}
public Asset fetchActiveByHostname(String hostname)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Hostname == hostname && a.IsDeployed == true
select a;
return query.FirstOrDefault();
}
public ICollection<Asset> fetchByHostname(String hostname)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Hostname == hostname
select a;
return query.ToList();
}
}
Дизайн 2
Во второй попытке я подумал, что смогу воспользоваться специальным полиморфизмом, обернув примитивные типы, используемые в качестве параметров:
public interface IAssetRepository
{
public Asset fetch(SerialNumber serialNumber);
public Asset fetch(Barcode barcode);
public ICollection<Asset> fetch(Hostname hostname);
public Asset fetchActive(Hostname hostname);
}
public class SerialNumber
{
private String value;
public SerialNumber(String value)
{ this.value = value; }
public String Value
{
get { return this.value; }
}
}
// Barcode and Hostname classes are similar to SerialNumber
public class AssetRepository : IAssetRepository
{
private InventoryEntites entities;
public Asset fetch(SerialNumber serialNumber)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.SerialNumber == serialNumber.Value
select a;
return query.FirstOrDefault();
}
public Asset fetch(Barcode barcode)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Barcode == barcode.Value
select a;
return query.FirstOrDefault();
}
public ICollection<Asset> fetch(Hostname hostname)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Hostname == hostname.Value && a.IsDeployed == true
select a;
return query.FirstOrDefault();
}
public Asset fetchActive(Hostname hostname)
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Hostname == hostname.Value
select a;
return query.ToList();
}
}
Дизайн 3
В духе «говори, а не спрашивай» мой последний дизайн перемещает фактические запросы в классы SerialNumber, Hostname и Barcode вместо того, чтобы запрашивать у них их значения. Классы SerialNumber и т. д. теперь должны содержать ссылку на источник данных. Они, вероятно, выиграют от того, что они будут интерфейсами, чтобы они могли поддерживать разные источники данных. Я не знаю, хороший ли это дизайн, потому что у каждого из них есть отдельная ссылка на сущности. Клиенты должны создать объекты (серийный номер и т. д.) перед отправкой их в репозиторий. Поскольку у клиентов не будет ссылки на сущности, та же самая ссылка на сущности не может быть внедрена во время построения:
// Same interface as last
public interface IAssetRepository
{
public Asset fetch(SerialNumber serialNumber);
public Asset fetch(Barcode barcode);
public ICollection<Asset> fetch(Hostname hostname);
public Asset fetchActive(Hostname hostname);
}
// Could include other methods like, findStartingWith(), findContains(), etc.
public class SerialNumber
{
private InventoryEntites entities;
private String value;
public SerialNumber(String value)
{
this.value = value;
this.entities = new InventoryEntities();
}
public Asset find()
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.SerialNumber == this.value
select a;
return query.FirstOrDefault();
}
}
// Barcode classes is similar to SerialNumber
public class Hostname
{
private InventoryEntites entities;
private String value;
public Hostname(String value)
{
this.value = value;
this.entities = new InventoryEntities();
}
public ICollection<Asset> find()
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Hostname == this.value
select a;
return query.ToList();
}
public Asset findActive()
{
IQueryable<Asset> query = from a in this.entities.Assets
where a.Hostname == this.value && a.IsDeployed == true
select a;
return query.FirstOrDefault();
}
}
public class AssetRepository : IAssetRepository
{
private InventoryEntites entities;
public Asset fetch(SerialNumber serialNumber)
{
return serialNumber.find();
}
public Asset fetch(Barcode barcode)
{
return barcode.find();
}
public ICollection<Asset> fetch(Hostname hostname)
{
return hostname.find();
}
public Asset fetchActive(Hostname hostname)
{
return hostname.findActive();
}
// Other methods could include
public ICollection<Asset> fetch(Location location)
{
return location.find();
}
public ICollection<Asset> fetchActive(Location location)
{
return location.findActive();
}
}
Обновлять
Проведя небольшое исследование, я нашел эту статью:
MSDN: шаблоны на практике: связность и взаимосвязь
Эта цитата натолкнула меня на мысль о Дизайне 3. Возможно, эту небольшую группу классов следует объединить в дизайн, более похожий на Дизайн 2?
Операция дробовика Определенный тип изменений в системе неоднократно приводит к внесению множества мелких изменений в группу классов. Хирургия дробовика обычно подразумевает, что одна логическая идея или функция распределены по нескольким классам. Попробуйте исправить это, объединив все части кода, которые должны измениться, в один связный класс.
getX
4get
методам. - person Brad Christie   schedule 02.04.2013getX
перегруженным методамget
? - person TheSecretSquad   schedule 02.04.2013getX
более подробно описывает, что делает метод, ИМХО. ВидяObjectA get(ObjectB obj)
, я почти задаюсь вопросом, что делает метод, тогда какObjectA getByObjectB(ObjectB obj)
уверяет меня, что он использует параметр в качестве фильтра. Работая с WCF и не всегда имея комментарии, на которые можно положиться, [небольшая] дополнительная работа того стоит, когда дело доходит до удобочитаемости позже. - person Brad Christie   schedule 02.04.2013