2015-12-15 18 views
11

Birden çok Closeable kaynağını yöneten bir Java sınıfı oluşturmaya çalışıyorum.Java'da kapatılabilir nesneler nasıl oluşturulur?

Benim saf Java çözüm
class composed_resource 
{ 
    resource_a a; 
    resource_b b; 
    resource_c c; 

    composed_resource(int x) 
     : a(x), b(x), c(x) 
    { } 

    ~composed_resource() 
    { } 
}; 

:

public class ComposedResource implements Closeable 
{ 
    private final ResourceA a; 
    private final ResourceB b; 
    private final ResourceC c; 

    public ComposedResource(int x) /* throws ... */ { 
     a = new ResourceA(x); 
     try { 
      b = new ResourceB(x); 
      try { 
       c = new ResourceC(x); 
      } catch (Throwable t) { 
       b.close(); 
       throw t; 
      } 
     } catch (Throwable t) { 
      a.close(); 
      throw t; 
     } 
    } 

    @Override 
    public void close() throws IOException { 
     try { 
      a.close(); 
     } finally { 
      try { 
       b.close(); 
      } finally { 
       c.close(); 
      } 
     } 
    } 
} 

Biraz geliştirilmiş versiyonu:

public class ComposedResource2 implements Closeable 
{ 
    private final ResourceA a; 
    private final ResourceB b; 
    private final ResourceC c; 

    public ComposedResource2(int x) /* throws ... */ { 
     try { 
      a = new ResourceA(x); 
      b = new ResourceB(x); 
      c = new ResourceC(x); 
     } catch (Throwable t) { 
      close(); 
      throw t; 
     } 
    } 

    @Override 
    public void close() throws IOException { 
     try { 
      if (a != null) a.close(); 
     } finally { 
      try { 
       if (b != null) b.close(); 
      } finally { 
       if (c != null) c.close(); 
      } 
     } 
    } 
} 

orada mı C++ çözüm basit ve kaynakların daha büyük bir sayı ile kolayca ölçeklenebilir olurdu hala istisna güvenliği korurken, yuvalanmış try-catch-blokları önleyen daha zarif çözüm? Üç kaynakla yönetilebilir, ama daha fazlası bir şey işe yaramıyor. (Yerel bir kapsam olsaydı, ben sadece bir "denemek-ile-kaynaklar" deyimi kullanabilirsiniz, ama bu burada geçerli değildir.) java.rmi ile çalışırken ben bu konuda düşünce


. Kurucuda, kayıt oluşturup/ararken, nesneleri ararken ve nesnelere ihracat yapıyorum. Close() öğelerinin kaydını kaldırması ve geri göndermesi gerekir. Ben ihracat/unexport işlemek için sarıcı nesneleri oluşturmayı düşündüm (RAI'dan yararlanmak için C++'da yaptığım gibi), ama sonra bana çok fazla yardımcı olmayacağını fark ettim (bir Java uzmanı değilim, ama bunu üniversite için kullanmalıyım).

Şu anda ComposedResource2 gibi bir şey kullanıyorum ve iyi çalışıyor. Ama şimdi daha zarif bir çözüm olup olmadığını bilmek istiyorum.

+2

Kullanım örneği sunabilir misiniz? Belki de somut bir örnekle çalışmak, soyut bir problemden daha iyi bir cevap üretecektir ... –

+1

Neden kaynak ile denenmesi uygun değil? –

+2

1) Kurucularda kaynak yaratmamaktan kaçının - ideal olarak, alanlara parametreler atamaları ve RAII'in burada geçerli olmadığını düşünüyorum. 2) Mümkünse kaynakları deneyin (eğer kurucunuz sadece “atama modunda” çalışacaksa sizin için daha uygun olacaktır). 3) Birden fazla 'Kapatılabilir 'örneğini tek bir örnekte birleştiren' Kapatılabilir' dekoratörünüzü yazabilirsiniz. 4) Ya da Guava 'com.google.common.io'yu kullanabilirsiniz.Closer'. –

cevap

11

Bunu benzer şekilde deneyin.

@Override 
public void close() throws IOException { 
    try (Closeable cc = c; 
     Closeable bb = b; 
     Closeable aa = a;) { 
     // do nothing 
    } 
} 
+0

Başlatma hataları nedeniyle kaynak boşsa ne olur? – AdamSkywalker

+2

@AdamSkywalker Eğer b boş, a ve c kapatılacak. – saka1029

+2

@AdamSkywalker 'kaynakları ile çalıştır 'Java'da null-safe: all' cc ',' bb 've' aa 'null olsa bile hiçbir şey başarısız olmaz. Ayrıca, başlatılmamış veya kötü başlatılmış nesneler kullanılmamalı ve bir başlatma özel durumu atılmamalıdır. En iyi durum her zaman iyi başlatılmış nesnelerdir. –

1

Bu yolla close() nasıl değiştirilir?

@Override 
public void close() { 
    close(a); 
    close(b); 
    close(c); 
} 

public void close(Closeable closeable) throws IOException{ 
     if (closeable != null){ 
      closeable.close(); 
     } 
} 

ben istediğiniz kadar ComposedResource gibi birçok kaynağa sahip olacak, böylece onun daha temiz ...

Ayrıca 'Closeables' olarak 3 kaynakları yönetmek ve onları bir diziye koymak düşünüyorum. Böyle bir şey yapmak:

ComposedResource c = new ComposedResource(); 
c.add(new Resource1()); 
c.add(new Resource2()); 
c.add(new Resource3()); 
... 
// do nice thinks 
// and, to close; 
c.close(); 

Düzenleme:: @Mohit Kanwar özel durum önerir

, bu şekilde:

@Override 
public void close() throws IOException { 
    for (Closeable r : resources){ 
     r.close(r); 
    } 
} 

public class ComposedResource{ 
    List<Closeable> resources = new ArrayList<Closeable>(); 

    public void add(Closeable c){ 
     resources.add(c); 
    } 

    @Override 
    public void close(){ 
     for (Closeable r : resources){ 
      close(r); 
     } 
    } 

    public void close(Closeable c){ 
     try{ 
      c.close(); 
     catch (IOException e){ 
      log(e); 
     } 
    } 
} 

Yani kaynak katacak

Ve kodumu düzenledim, @Lii bu bir istisnayı yapmanın tüm kaynakları kapatmayı önleyeceğini ve Wi Bu yüzden Lii, Mohit'in düzenlemesini reddettim ...

+2

Bir kaynak kapatılmıyorsa, günlük kaydettikten sonra istisnayı e atmamalı mıyız? –

+3

Çözümünüzde, ilk kaynak kapatıldığında atarsa, sonraki kaynaklar kapanmaz. Bu nasıl çalışması gerektiği değil! – Lii

+0

@inigoD Şimdi anlıyorum. Yanlış düzenleme için üzgünüm. Size bir fiyat düşürdüğünden beri bir bayrak çıkardım. Özür tekrar :( –

İlgili konular