2016-09-18 3 views
1

常に同じです。変更できる唯一のものは、ファイルの場所です。つまり、ローカルシステム上のファイルまたはURLである可能性があります。Javaサービス・アーキテクチャ

class AbstractFooService implements FooService { 

    Map<Bar, Foo> registry; 

    AbstractFooService(InputStream is) { 
     try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { 
      registry = reader.lines() 
       .map(l -> l.split(';')) 
       .map(a -> new Foo(a[0]), a[1])) 
       .collect(Collectors.groupingBy(...)); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    } 

    Optional<Foo> getFoo(Bar bar) { 
     return Optional.ofNullable(registry.get(bar)); 
    } 
} 

コンクリート実装がただのInputStreamとスーパーのコンストラクタを呼び出します:だから私はAbstractFooServiceを作成し

class UrlFooService extends AbstractFooService { 
    UrlFooService(String url) { 
     super(createStream(url)); 
    } 

    private static InputStream createStream(final String url) { 
     try { 
      return new URL(string).openStream(); 

     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    } 
} 

サウンドAPIの設計やが私の目標を達成するために、「より良い」方法があるということです?私。 InputStreamでスーパーコンストラクタを呼び出すことは賢明ですか、必要なときにストリームを開く別のload()メソッドを持つ方がよいでしょうか?

+3

作業コードについては、codereview.stackexchange.comを参照してください。 – GhostCat

+0

コンストラクタでの作業は、一般的には悪い考えです。これはコードをテストするのが難しくなり、継承階層で明白でない動作を引き起こす可能性があります。 – sisyphus

答えて

2

そこに抽象基本クラスが必要な理由はわかりません。継承よりも構成を優先する。私は、より合理的な解決策を持っているだろうと思う:

public class FooServiceImpl implements FooService { 
... 

そして、このような

public class UrlFooService implements FooService { 
    private final FooService delegatee; 

public UrlFooService(URL url) { 
    delegate = new FooServiceImpl(url.openStream()) 
... 
@Override 
Optional<Foo> getFoo(Bar bar) { return delegatee.getFoo(bar); } 

継承カップルその親クラスを使用して、具体的なサービスクラスなどのクライアント。このシンプルな「委任」メカニズムを使用することで、避けたいと思います。

ご注意:私はまた、URLを取るためにUrlSerivceのctorのを変更しました。あなたはすでにそこにタイプがあるので、どうして自分自身を新しいものと呼ぶのは気にかかりますか?それはあなたのUrlServiceが間違っている可能性のあるすべてのものを処理しなければならないことを意味します。

0

あり、ここであなたの質問と課題のカップルだと私は少し違った問題を分解することから始めます。 @sisyphusとして

あなたは、コンストラクタでやっているそれらのものに気をつけ、と述べました。コンストラクタは本当に "有効なオブジェクト"を作成するだけで、それ以上は何も作成しないようにする必要があります。 @GhostCatの良いアイデアもたくさんあります。

は、代わりに次のような問題をモデル化を考える:

はあなたのサービスのためのAPIを表すインターフェイスを作成します。この場合、それを "getFoo()"にしたい場合は偉大です。あなたが渡したいもの(実際にはファイルかURLかパスか)を考えてみましょう。あなたはそれが大きなファイルだと言っていたので、大きなオブジェクトをメモリにインスタンス化して、それを再び便利なフォーマットに構文解析するつもりはないかもしれません。あなたは間違いなくガベージコレクションで価格を支払うでしょう。

次は、ファイルの「発見」を分離すると考えてください - または解析ロジックでストリームを開きます。見つからない、アクセス権を持たない、開かれたファイルが多すぎる(ulimit)など、単にファイルを開こうとするときに発生する可能性のある例外はたくさんあります。

それはパースに来るとき、私はあなたが解析し、何のためにしているもので、実際に明確に取得するために検討することをお勧めします。これが実際の問題であれば、「安定したフォーマット」は常に変更される可能性があります。特に、印刷不可能な文字や予期しないEOFの存在など、「無効な」フォーマットを許容する場合は特に変わりません。正常に処理することが求められ、また何が解析されたのか、エラーがあったのか、それを処理するのかを理解する必要があります。

私の2セント。

関連する問題