2010-06-12 14 views
6

Sorularımın kelimeleri kullanarak açıklamak kolay değildir, neyse ki gösterilmesi çok zor değildir. Yani, bana ayı:İstenilen sonucu elde etmek için jenerik ve kalıtım düzgün şekilde nasıl karıştırılır?

public interface Command<R> 
{ 
    public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command 
} 

public abstract class BasicCommand<R> implements Command<R> 
{ 
} 

public interface CommandProcessor<C extends Command<?>> 
{ 
    public <R> R process(C<R> command);//this is my question... it's illegal to do, but you understand the idea behind it, right? 
} 

//constrain BasicCommandProcessor to commands that subclass BasicCommand 
public class BasicCommandProcessor<C extends BasicCommand<?>> implements CommandProcessor<C> 
{ 
    //here, only subclasses of BasicCommand should be allowed as arguments but these 
    //BasicCommand object should be parameterized by R, like so: BasicCommand<R> 
    //so the method signature should really be 
    // public <R> R process(BasicCommand<R> command) 
    //which would break the inheritance if the interface's method signature was instead: 
    // public <R> R process(Command<R> command); 
    //I really hope this fully illustrates my conundrum 
    public <R> R process(C<R> command) 
    { 
     return command.execute(); 
    } 
} 

public class CommandContext 
{ 
    public static void main(String... args) 
    { 
     BasicCommandProcessor<BasicCommand<?>> bcp = new BasicCommandProcessor<BasicCommand<?>>(); 
     String textResult = bcp.execute(new BasicCommand<String>() 
     { 
      public String execute() 
      { 
       return "result"; 
      } 
     }); 
     Long numericResult = bcp.execute(new BasicCommand<Long>() 
     { 
      public Long execute() 
      { 
       return 123L; 
      } 
     }); 
    } 
} 

Temelde, jenerik "süreç" yöntemi Komut nesnesinin jenerik parametrenin türünü dikte etmek istiyorum. Amaç, CommandProcessor'un farklı uygulamalarını Komuta arabirimini uygulayan belirli sınıflara kısıtlayabilmek ve aynı zamanda CommandProcessor arabirimini uygulayan herhangi bir sınıfın işlem yöntemini çağırabilmek ve belirtilen nesne türünü döndürmesini sağlamaktır. parametarized komut nesnesi. Açıklamamın yeterince açık olup olmadığından emin değilim, bu yüzden daha fazla açıklama gerekirse lütfen bana bildirin. Sanırım, soru şu ki: "Bunu yapmak mümkün mü acaba?" Cevabınız "Hayır" ise, en iyi iş ne olurdu (kendi başıma bir çift düşündüm, ama yeni fikirler istiyorum)

+0

BasicCommand, 'Command' komutunu uygulamamalı mı? –

+0

Touche, düzeltildi. Onu yakaladığın için teşekkürler! – Andrey

cevap

3

Maalesef bunu yapamazsınız. Command açısından tanımlanacak CommandProcessor arabirimini istediğinizden, her türlü Command örneğini almanız için hazırlamanız gerekir - jenerik bu durumu BasicCommand ile sınırlayamaz - eğer yapabilirse, BasicCommandProcessor alt sınıfı CommandProcessor arabirimini uygulamaz. Veya bir CommandProcessor arabirimi verildiğinde, başka bir açıdan bakıldığında, bunun yalnızca BasicCommand örnekleri ile çağrıldığından emin olmaları mümkün değildir. Bunu yapmak için implementasyonu bilmek ve polimorfizm ve arayüzler noktasına karşı gitmek gerekir.

Komutun sonucunu parametreleştirebilirsiniz, ancak komutun somut sınıfını değil.

public interface Command<R> 
{ 
    public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command 
} 

public abstract class BasicCommand<R> implements Command<R> 
{ 
} 

public interface CommandProcessor 
{ 
    public <R> R process(Command<R> command); 
} 

public class BasicCommandProcessor implements CommandProcessor 
{ 
    public <R> R processBasicCommand(BasicCommand<R> command) 
    { 
     return command.execute(); 
    } 

    public <R> R process(Command<R> command) 
    { 
     return processBasicCommand((BasicCommand<R>)command); 
    } 
} 

en basit yaklaşım, gereken özel tip kabul eden bir yöntem sağlar ve jenerik yöntemde öyle hitap etmektir. (Yukarıda BasicCommandProcessor bakınız.)

+0

"jenerik bu sadece BasicCommand örnekleriyle çağrıldı sağlamak için ... Bir CommandProcessor arayüzü göz önüne alındığında, bu mümkün değil. Bu implemnetation bilmesi gerekir ve polimorfizm ve arayüzler noktasına karşı gideceğini yapmak için." Tabiki öyle. Uygulama, tip parametresi olarak belirtilirse, bir alt sınıf, türü bağlı olarak daha fazla kısıtlayabilir, örneğin benim cevabımı görebilir. Evet, bu, ham türlerin ikame prensibine uymadığı ve derleyicinin yöntem argümanını yayınlamak için sentetik bir yöntem yayması gerektiği anlamına gelir. Ama geçerli bir Java. – meriton

+0

Ne dediğini görüyorum. Uygulama detayları için ek parametre tipleri ekleyerek çalışmak mümkün olabilir, ancak bana bir arayüze sahip olmaktan uzaklaşır. Benim deneyimime göre, arayüzlerin sayısı arttıkça çalışmak da hantal hale gelebilir. – mdma

+0

Bu niyete bağlıdır. Eğer CommandProcessor, arayüzde komut tipine sahip her türlü komut ile çalışabilirse gerçekten işe yaramaz. Ancak, bir Komuta İşlemcinin yalnızca belirli komut türleriyle çalışabilmesi durumunda (burada göründüğü gibi), arayüzde bunun uygun olabileceğini ifade etmek mümkündür. Bir CommandProcessor, böyle bir gerçek türü başlatmasını ("jenerik paralel sınıf hiyerarşileri tasarlama yardıma mı?" http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html de bakınız) – meriton

1

Temelde, genel "işlem" yöntemi komut nesnenin genel parametresinin türü dikte istiyoruz. Bir CommandProcessor başlatmasını olduğunda, gerçek bir tipi, örneğin Command<String>C için temin edilebilir:

Bu parça tipine tipi parametre olarak komut tanımlama kavramı ile çelişmektedir. Hatta C<R> anlamı, sonra ne olurdu

class Foo implements Command<String> { 
    ... 
} 

gibi olmayan bir genel tür tedarik etmek mümkün olurdu? Foo<R>? Command<String><R>? Command<R>?

Hangi seçenekleriniz var? Bir CommandProcessor sadece belirli dönüş türü ile çalışmak gerekiyorsa, bunu yapabilirsiniz:

class CommandProcessor<R, C extends Command<R>> { 
    R process(C command); 
} 

class FancyCommandProcessor<R, C extends FancyCommand<R>> extends CommandProcessor<R,C> { 

} 

Ancak, sana bir CommandProcessor komutların tamamı tip aile ile çalışmak istiyoruz şüpheli.Tek başına bu, hiçbir sorun olacağını basitçe beyan ederiz:

<R> R process(FancyCommand<R> command); 

Ancak varsa, process geçersiz böylece ek komutlar farklı aileler için CommandProcessors arasında bir alt tür ilişki istiyorum, Java jenerik belirginliğinde ötesinde girişim. Özellikle, C++ 'template' türündeki parametrelere (gerçek tip argüman olarak bir şablon iletmesine izin veren) veya Komutu genişleteceği bilinen gerçek tip argümanı verilen komutun tip parametresini yakalama yeteneğine ihtiyacınız vardır. . Java da desteklemiyor.

+0

"Yani, Command olarak olmalıdır C " için sağlanmıştır. Yanlış, hatalısınız. Bir [wild card] (http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html) (Komut ) her zaman temin edilebilir ... – Andrey

+0

Düzeltilmeye devam ettim ve buna göre düzenledim. Ancak, benim argümanımda çok az değişiyor ... – meriton

+0

Problemi iyi tanımladınız. Tek şey CommandProcessor aslında başa olabilir Komutanlığı dönüş türü hakkında bilmek gerekmez olduğunu değil, yazın nesne üzerinde geçmek sadece ihtiyacı bu durumda işlemeden geldiğinde haricinde hangi komut ile görünmesi mümkün olmayan parametrelenmişti. Cevap ver, geri çekilin. – Andrey

İlgili konular