2016-06-10 3 views
1

Я использую библиотеку GeoJSON.NET в своем проекте. В какой-то момент мне нужно обновить функцию в моей базе данных. Как часть этого, мне нужно получить доступ к координатам указанной функции, чтобы сохранить эту информацию в базе данных. Однако, глядя на исходный код на GitHub, класс Feature имеет свойство Geometry как IGeometryObject:Литой интерфейс для конкретного типа

public IGeometryObject Geometry { get; set; } 

Там существует несколько «форм» в соответствии со спецификацией GeoJSON, такие как «Полигон», «Круг», «Точка »и т. д. Эти конкретные формы были созданы в рамках проекта GeoJSON.NET.

Именно в этих конкретных типах я могу на самом деле копаться и получать доступ к различным координатам.

В настоящее время у меня есть это:

public int CreateFeature(Feature feature) 
    { 
     int featureId = 0; 
     var coordinatesDt = new DataTable(); 
     coordinatesDt.Columns.Add("Latitude"); 
     coordinatesDt.Columns.Add("Longitude"); 

     //we are loading a datatable with the coordinates. This gets passed to a SQL server stored procedure as a single parameters to insert 
     //all the nodes. 
     LineString lineString = ((Polygon)feature.Geometry).Coordinates[0]; 
     foreach (var coordinate in lineString.Coordinates) 
     { 
      var row = coordinatesDt.NewRow(); 
      row["Latitude"] = ((GeographicPosition)coordinate).Latitude; 
      row["Longitude"] = ((GeographicPosition) coordinate).Longitude; 
      coordinatesDt.Rows.Add(row); 
     } 


     using (SqlConnection conn = new SqlConnection(_smmConnectionString)) 
     using (SqlCommand cmd = new SqlCommand("dbo.MyProc", conn)) 
     { 
      //set up params, set up TVP and execute... 
     } 
     return featureId; 
} 

А вот фрагмент из класса Polygon:

public List<LineString> Coordinates { get; set; } 

Так вот в моем коде, я на самом деле делает явный опущенными к Polygon, как Мне нужно добраться до члена Координаты класса Polygon. Я знаю, что я в безопасности, чтобы сделать это только на том основании, что это единственные «типы» форм, которые я использую в своем приложении, хотя я знаю, что это не обязательно лучшая практика. Однако в будущем, если мы будем использовать другие типы, это будет полностью нарушено. Я могу пойти реализовать, используя «is или as» для проверки типов, но это все еще не отвлекает меня от понятия «downcast».

Итак, мой вопрос - это лучший способ сделать это? Я читал о том, почему использовать интерфейсы и все это как члены и/или параметры, и что необходимость делать явное опустошение - это обычно «плохая практика» и следует за плохим шаблоном проектирования ... за исключением редких случаев. Так что я попадаю в «редкие случаи» здесь или есть лучший способ сделать это?

ответ

1

Основываясь на API GeoJSON.NET, я думаю, что вы попадаете в один из этих «редких случаев». У вас есть несколько вариантов решения этой проблемы:

  1. Добавить оператор switch в метод CreateFeature, который отправляет метод, специфичный для формы. Переместите функциональность, специфичную для формы, в метод, специфичный для формы (см. Ниже).
  2. Создайте серию if..else, если это проверит тип для определенных типов (например, if (shape is Polygon) ProcessShape((Polygon)shape);) и отправьте метод, специфичный для формы.
  3. Используйте шаблон посетителя, чтобы отправить его на конкретный метод (хотя для этого потребуется изменить код библиотеки GeoJSON.NET).

Пример кода для варианта 1:

switch (shape.Type) 
{ 
    case GeoJSONObjectType.Polygon: 
     ProcessShape((Polygon)shape); 
     break; 
    // additional shape support here... 
} 

Пример кода для варианта 3:

// Add an AcceptVisitor method to the IGeometryObject interface: 
public interface IGeometryObject 
{ 
    GeoJSONObjectType Type { get; } 
    void AcceptVisitor(IShapeProcessor visitor); 
} 
// Update each concrete shape class to include the new AcceptVisitor method: 
public void AcceptVisitor(IShapeProcessor visitor) 
{ 
    visitor.ProcessShape(this); 
} 
// Add an IShapeProcessor interface to the GeoJSON.NET project: 
public interface IShapeProcessor 
{ 
    void ProcessShape(Polygon shape); 
    void ProcessShape(MultiPoint shape); 
    void ProcessShape(LineString shape); 
    // ...additional shape support... 
} 
// Update your existing class to implement the IShapeProcessor interface, 
// and then change your code to do something like: 
feature.Geometry.AcceptVisitor(this); 

... и если вы идете с вариантом 3, отправить запрос тянуть на GitHub так что каждый может воспользоваться вашими улучшениями!

+0

Спасибо за отзыв! Я очень благодарен. Из-за ограничений по времени, а также так мало вариантов для типов фигур, я, вероятно, просто придерживаюсь опции 1. – dvsoukup

+0

Викинг и изменение внешнего api - довольно плохая идея, так как это становится намного сложнее в обслуживании (обновление до новых версии). Если вы поедете по этой дороге, вы действительно можете добавить недостающую функцию, которую вы хотите в интерфейсе: GetGeoPosition() –

+0

Я думаю, что GetGeoPosition() и настройка в каждом конкретном типе были бы ключевым аспектом здесь и помогли бы, не имея чтобы переусердствовать с получением этих координат. Благодаря! – dvsoukup

1

Итак, вы решили, что вам нужно получить доступ к внутренней детали реализации какого-либо интерфейса elses, который вы не можете изменить.

Тогда у вас действительно нет выбора, кроме как взять на себя расходы на последующее обслуживание. Да, у вас есть один из тех редких случаев.

Чтобы свести к минимуму затраты, я настоятельно рекомендую вам обернуть весь опасный код в вспомогательный класс, который работает с опубликованным интерфейсом, поэтому вы не будете смешивать его с собственной бизнес-логикой и четко видеть, где вам нужно вносить изменения в будущем.

+0

Спасибо за это. Вы в основном сказали, что @wablab дал в качестве примеров. Мне понадобился еще один набор глаз, чтобы сказать мне, что это на самом деле один из тех редких случаев. – dvsoukup

Смежные вопросы