Scala API дизайн; сервис, который возвращает Set <I>, где I - некоторый интерфейс (аннотация / черта) - PullRequest
1 голос
/ 25 марта 2009

Я задал довольно много вопросов о типах коллекций Scala и о том, как они могут быть использованы на самом деле. Подумайте, как я мог бы написать какой-нибудь сервис API / реализацию на Java:

public interface JavaProductAPI {
     public Set<IProduct> getProducts(String isin);
}

А теперь импл:

public class JavaProductAPIImpl implements JavaProductAPI {
    private Map<String, Set<ProductImpl>> productsByIsin;

    public Set<IProduct> getProducts() {
        Set<ProductImpl> s = productsByIsin.get(isin);
        return s == null 
                   ? Collections.<IProduct>emptySet()
                   : Collections.<IProduct>unmodifiableSet(s);
    }

}

Допустим, есть действительно веская причина, по которой мне нужно иметь доступ в реализации сервиса к набору продуктов как ProductImpl с, а не IProduct с.

Кажется, что в Scala нет реального способа достичь этого, в то же время явно возвращая scala.collection.immutable.Set из метода доступа API. Если я не против вернуть копию набора .

Я собираюсь предположить, что возвращать фактическую копию данных - плохая практика (не стесняйтесь спорить об этом!):

val productsByIsin: Map[String, scala.collection.Set[ProductImpl]] = ...
def getProducts(isin: String): scala.collection.immutable.Set[IProduct] = {
  productsByIsin.get(isin) match {
     case Some(s) => scala.collection.immutable.Set(s toSeq :_*)
     case None => scala.collection.immutable.Set.empty
  } 
}

Таким образом, поэтому мой единственный реальный выбор дизайна - API вернуть scala.collection.Set и использовать представление только для чтения:

val productsByIsin: Map[String, scala.collection.mutable.Set[ProductImpl]] = ...
def getProducts(isin: String): scala.collection.Set[IProduct] = {
  productsByIsin.get(isin) match {
     case Some(s) => s readOnly
     case None => scala.collection.Set.empty
  } 
}

1 Ответ

2 голосов
/ 25 марта 2009

Ваш последний блок кода более точно имитирует код Java, который вы эмулируете: возвращая доступное только для чтения представление изменяемого набора.

Тем не менее, в этой ситуации, если ваша вспомогательная реализация является неизменяемой. Установите [ProductImpl] и вы хотите вернуть неизменяемый. Установите [IProduct], безопасное приведение.

import scala.collection._

trait IProduct
class ProductImpl extends IProduct

val productsByIsin: immutable.Map[String, immutable.Set[ProductImpl]] =
  immutable.Map.empty
def getProducts(isin: String): immutable.Set[IProduct] =
  productsByIsin.getOrElse(isin, immutable.Set.empty).asInstanceOf[immutable.Set[IProduct]]
...