“Statik arayüz” iyi bir uygulama mı?


13

Son zamanlarda arayüzlerde statik yöntemlere sahip olmak için bir seçenek olduğunu fark ettim. Arayüzün statik alanları ile aynı, ilginç bir davranış vardır: Bunlar kalıtsal değildir.

Uygulanacak gerçek arayüzlerde herhangi bir yararlı olduğundan emin değilim. Bununla birlikte, programlayıcının, örneğin, yardımcı sınıflar gibi, statik şeyler için yalnızca zarf olan arabirimler oluşturmasını sağlar.

Basit bir örnek sadece küresel sabitler için bir zarftır. Bir sınıfa kıyasla, eksik olan kazan plakasını public static finalvarsayıldığı gibi kolayca fark edebilirsiniz (daha az ayrıntılı hale getirir).

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

Yapılandırma anahtarlarının sözde enumumu gibi daha karmaşık bir şey de yapabilirsiniz.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

Ayrıca bu şekilde bazı "sınıf" yardımcı programı da oluşturabilirsiniz. Bununla birlikte, kamu hizmetlerinde, sınıflarda tam olarak mümkün olmayan özel veya korumalı yardımcı yöntemleri kullanmak genellikle yararlıdır.

Bunu yeni ve güzel bir özellik olarak görüyorum ve özellikle statik üyelerin miras alınmaması sadece arayüzlere tanıtılan ilginç bir kavram.

Acaba bunu iyi bir uygulama olarak değerlendirebilir misin? Kod stili ve en iyi uygulamalar aksiyomatik olmasa da, görüş için yer olsa da, genellikle görüşü destekleyen geçerli nedenler olduğunu düşünüyorum.

Bu ikisi gibi kalıpları kullanmanın nedenleriyle (değil) daha çok ilgileniyorum.


Bu arayüzleri uygulamak istemediğimi unutmayın. Onlar sadece statik içeriği için bir zarf. Ben sadece sabitleri veya yöntemleri kullanmak ve muhtemelen statik içe aktarma kullanmak niyetinde.


1
Bunun diz pisliği tepkisi sadece kötü şeylere yol açabileceğidir. Her ne kadar kamusal statik yöntemler temelde sadece isimlendirilmiş küresel işlevler olsa da. Bir Arayüzdeki herhangi bir uygulama kodunun, bir sözleşme tanımı bulunmadığı için amacına aykırı olmasına izin vermek gibi görünüyor. Soyut derslere kısmi uygulama bırak diyorum. Bunun neden eklendiğini okumam gerekecek.
Adrian

Şimdilik gitmek zorundayım ama yarın üzerine bir şeyler yazacağım. Kısacası, bir Arayüzün bir AbstractClass'ın amacından açıkça ayrılan net bir amacı yoktu. Şimdi bir Arayüzün dil agnostik tanımını ihlal edecek şekilde büyük ölçüde örtüşüyorlar. Ayrıca, varsayılan yöntemleri uygularsa artık birden çok arabirimden devralmadığınız durumlar da vardır. Yani artık eskiden olmadığı çoklu arayüz devralma istisnaları var. Java bir arabirimin ortak tanımından büyük ölçüde saptığından ...
Adrian

Arayüzler, AbstractClases gibi temel OOP kavramlarını doğru bir şekilde ele almaya çalışan yeni geliştiricileri, kalıtım yerine kompozisyonun ne zaman kullanılacağını, vb.
Adrian

Aliester, defaultyöntemlerden bahsediyorsun . staticYöntemler ve alanlar hakkında konuşuyorum . Bunlar miras alınmaz, bu yüzden çoklu mirastan kopmazlar.
Vlasec

Yanıtlar:


1

Basit bir örnek sadece küresel sabitler için bir zarftır.

Sabitleri arayüzlere koymaya denir, Constant Interface Antipatternçünkü sabitler genellikle sadece bir uygulama detayıdır. Diğer dezavantajlar, Constant arayüzü hakkındaki Wikipedia makalesinde özetlenmiştir .

Ayrıca bu şekilde bazı "sınıf" yardımcı programı da oluşturabilirsiniz.

Aslında, Java dokümanı , statik yöntemlerin yardımcı yöntemleri düzenlemeyi kolaylaştırabileceğini, örneğin yardımcı yöntemleri varsayılan yöntemlerden çağırırken kolaylaştırabileceğini belirtir.


1
Bu yeni bir işlevsellik olmadan her ikisini de yapabileceğiniz için sorulan soruya bir cevap olduğunu düşünmüyorum.
Adrian

Ah, dokümantasyonla, yardımcı bir yöntem olarak düşünülmüş. Bununla birlikte, onunla çelişen kamuya da açıktır. Bu yüzden belki de arayüzü uygulayan sınıflara yardımcı olması amaçlanmıştır. Ancak kalıtsal değildir, bu nedenle miras aldığınız gibi hissettirmek için statik içe aktarma kullanmanız gerekir. Belgelere baktığın için teşekkürler.
Vlasec

2
Bu sabitler bir şekilde arabirim tarafından açıklanan API'nin bir parçasıysa, sabitleri arabirimlere koymakla ilgili kesinlikle yanlış bir şey yoktur. Antipattern olan tek şey, sabitleri yöntemsiz arabirimlere koymak ve sınıfların arabirimi yalnızca sınıf öneki olmayan sabitlere başvurmak için uygulamasını sağlamaktır. Arayüzlerin kötüye kullanılması ve statik ithalatın getirilmesinden bu yana tamamen eski.
Michael Borgwardt

1

Soruda belirtildiği gibi, arayüzün uygulanması (veya somutlaştırılması) amaçlanmamıştır. Böylece özel bir kurucuya sahip bir sınıfla karşılaştırabiliriz:

  • Sınıf, çağrılacak numara olmadan genişletilemez super(), ancak arabirim "uygulanabilir"
  • Arabirim yansımalar olmadan somutlaştırılamazken, arayüz anonim bir sınıf olarak bu kadar basit bir şekilde somutlaştırılabilir: new MyInterface() {};

Bu karşılaştırma daha fazla kontrole izin verdiği için sınıf lehinedir. Bununla birlikte, sınıfın statik şeylere de sahip olması amaçlanmamıştır, örneklerin olmasını beklersiniz. Mükemmel bir seçenek yok.

"Statik arayüz" ün kalıtımla ilgili garip bir yanı da var:

  • Bir "uygulayan" sınıfı alanları devralır, ancak statik yöntemleri devralmaz
  • Genişleyen arabirim hiçbir statik üyeyi devralmaz
  • (Bir sınıfı genişleten bir sınıf, özel olmayan her üyeyi devralırken ... ve bir arabirim tarafından genişletilemediğinden, karışıklığa daha az yer vardır)

Bunlar, bunun kötü bir model olduğunu düşünmek ve bu durumlar için statik sınıflar kullanmaya devam etmek için nedenler olabilir. Bununla birlikte, sözdizimsel şekere bağımlı biri için, olumsuz taraflarla bile cazip olabilir.


Her neyse, bir takımın kodlama kuralları bu sorunları kapsayabilir. Bana göre, bir programcının elini, özel kurucu ile bir sınıf kadar sıkı bir şekilde bağlamasa da, ayarlayıcılardan daha az risk taşıyor ve ayarlayıcılar sıklıkla kullanılıyor.
Vlasec

0

@MarkusPscheidt olarak bu fikir esasen Sabit Arayüz antipatisinin bir uzantısıdır . Bu yaklaşım başlangıçta tek bir sabit kümesinin birçok farklı sınıf tarafından miras alınmasına izin vermek için yaygın olarak kullanılmıştır. Bunun bir karşıtlık olarak kabul edilmesinin sebebi, gerçek projelerde bu yaklaşımla karşılaşılan sorunlardan kaynaklanıyordu. Bu sorunların sadece sabitlerle ilgili olacağını düşünmek için hiçbir neden göremiyorum.

Muhtemelen daha da önemlisi, bunu yapmaya gerek yok. Kullanım statik ithalatı yerine ve ithal ediyoruz ne olduğu ve nereden net yapın.


Evet, statik içe aktarma sesi, sabitlerin mirasından daha iyi bir fikir gibi görünür ve hem sınıfların hem de arabirimlerin statik üyeleriyle çalışan çalışır. Ve sadece sınıfın / arayüzün içinde görülebilir.
Vlasec

@Vlasec Doğru, ancak bunu bir arayüzde yapmaya gerek yok. Bunu bir sınıfla ve bir arabirimle yapmak arasındaki tek fark, birden fazla arabirimden miras alabilmenizdir. Bunun gibi bir yardımcı sınıf için standart uygulama, örneklemeyi veya genişletmeyi önlemek için yapıcıyı özel yapmaktır. Bunu bir sınıf üzerinden bir arayüzde yapmanın bir yararı yoktur. Sadece yanlış kullanım için kapıyı açar.
JimmyJames

Arayüzlerdeki sabitlerdeki değeri görebiliyorum. Arabirimler yöntemleri tanımlama eğilimindedir ve yöntemler bazen sabitleri parametre olarak kabul eder. Ör: interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }. Orada olmayı hayal edebilirsiniz bazı farklı sabitler RGB, RGBA, CMYK, GREYSCALE, INDEXEDvb
Stijn de Witt

@StijndeWitt Bu en kötü şey olmaz, ancak bu amaçla arabirimde bir enum veya iç içe sınıf kullanabilirsiniz. Asıl mesele bunu, kalıtım yoluyla statiki birçok sınıfın kapsamına getirmek için kullanmaktır. Bu yaklaşım statik ithalatın kullanımından açıkça daha düşüktür.
JimmyJames

0

Yeni özelliği doğru bir şekilde nasıl kullanacağınızla ilgileniyorsanız, JDK'daki koda bir göz atın. Arabirimlerdeki varsayılan yöntemler çok yaygın olarak kullanılır ve bulunması kolaydır, ancak arabirimlerdeki statik yöntemler çok nadir görülür. Bazı örnekler şunlardır java.time.chrono.Chronology, java.util.Comparator, java.util.Mapiçinde ve epeyce arayüzleri java.util.functionve java.util.stream.

İncelediğim örneklerin çoğu, çok yaygın olması muhtemel API'lerin kullanımını içerir: örneğin, işlevlere aktarılan nesneler veya içerilen nesneler arasında sık sık yapılması gereken karşılaştırmalar için zaman API'sındaki farklı türler arasında dönüşüm koleksiyonları. Benim paket programım: API'nizin esnek olması gereken bir parçası varsa, ancak kullanım durumlarının% 80'ini birkaç varsayılanı kapsayabilirse, arayüzlerinizde statik yöntemler kullanmayı düşünün. Bu özelliğin JDK'da ne kadar seyrek göründüğü göz önüne alındığında, kendi kodumda kullanırken çok muhafazakar olurum.

Örnekleriniz JDK'da gördüklerime benzemiyor. Bu özel durumlar için, neredeyse kesinlikle enumistenen arayüzü uygulayan bir tane oluşturmalısınız . Bir arabirim bir dizi davranışı açıklar ve uygulamalarının bir koleksiyonunu koruyan hiçbir işi yoktur.


-1

Kullanmamanın nedenleri var mı acaba?

Eski JVM'lerle uyumluluğa ne dersiniz?

Bunun genel olarak iyi bir fikir olduğunu düşünüyor musunuz?

Hayır. Bu, dilin ifadesine zilch ekleyen geriye doğru uyumsuz bir değişikliktir. İki başparmak aşağı.

Sınıfları şiddetle tavsiye ettiğiniz bazı model durumlar var mı?

Uygulama ayrıntılarını içermek için sınıfları kullanmanızı önemle tavsiye ederim. Bir arabirim gerçekten "bu Nesne XYZ işlemlerini destekler" demek içindir ve bunun arabirim bildirimine koymayı düşünebileceğiniz herhangi bir statik yöntemle ilgisi yoktur. Bu özellik, yerleşik bir mini buzdolabına sahip bir deniz yatağı gibidir. Tabii ki bazı niş kullanımları var ama ana akım olmayı hak edecek kadar ağırlık çekmiyor.

GÜNCELLEME: Lütfen daha fazla oy yok. Açıkçası bazı insanlar arayüzlerdeki statik yöntemlerin arının dizleri olduğunu düşünüyor ve ben de burada teslim oluyorum. Bu cevabı en kısa sürede silerdim ama ona eklenen yorumlar ilginç bir tartışma.


Yorumlar uzun tartışmalar için değildir; bu görüşme sohbete taşındı .
maple_shaft

Sorunuzu reddetseydim, bunu yapardım çünkü ilk iki cevabımız gerçek cevaplar değil. Dilin yeni sürümü, işleri kolaylaştırmak için yeni araçlar getiriyor, bu yeni sürümlerin amacı bu. Üçüncü cevap, ilk iki baskın molozunda kaybolur.
Vlasec
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.