मुझे सुरुचिपूर्ण के बारे में पता नहीं है, लेकिन यहां जावा के बिल्ट-इन का उपयोग करते हुए एक कार्यान्वयन है, java.lang.reflect.Proxyजो इस बात को लागू करता है कि राज्य की Fooजाँच करके सभी विधि चालान शुरू होते हैं enabled।
main तरीका:
public static void main(String[] args) {
Foo foo = Foo.newFoo();
foo.setEnabled(false);
foo.bar(); // won't print anything.
foo.setEnabled(true);
foo.bar(); // prints "Executing method bar"
}
Foo इंटरफेस:
public interface Foo {
boolean getEnabled();
void setEnabled(boolean enable);
void bar();
void baz();
void bat();
// Needs Java 8 to have this convenience method here.
static Foo newFoo() {
FooFactory fooFactory = new FooFactory();
return fooFactory.makeFoo();
}
}
FooFactory वर्ग:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class FooFactory {
public Foo makeFoo() {
return (Foo) Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[]{Foo.class},
new FooInvocationHandler(new FooImpl()));
}
private static class FooImpl implements Foo {
private boolean enabled = false;
@Override
public boolean getEnabled() {
return this.enabled;
}
@Override
public void setEnabled(boolean enable) {
this.enabled = enable;
}
@Override
public void bar() {
System.out.println("Executing method bar");
}
@Override
public void baz() {
System.out.println("Executing method baz");
}
@Override
public void bat() {
System.out.println("Executing method bat");
}
}
private static class FooInvocationHandler implements InvocationHandler {
private FooImpl fooImpl;
public FooInvocationHandler(FooImpl fooImpl) {
this.fooImpl = fooImpl;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Foo.class &&
!method.getName().equals("getEnabled") &&
!method.getName().equals("setEnabled")) {
if (!this.fooImpl.getEnabled()) {
return null;
}
}
return method.invoke(this.fooImpl, args);
}
}
}
जैसा कि दूसरों ने बताया है, यह आपको जरूरत के लिए ओवरकिल की तरह लगता है अगर आपको केवल कुछ ही तरीकों की चिंता करनी है।
उस ने कहा, निश्चित रूप से लाभ हैं:
- चिंताओं का एक निश्चित पृथक्करण हासिल किया जाता है, क्योंकि
Fooविधि के कार्यान्वयन को enabledचेक-कटिंग चिंता के बारे में चिंता करने की आवश्यकता नहीं है । इसके बजाय, विधि के कोड को केवल इस बारे में चिंता करने की आवश्यकता है कि विधि का प्राथमिक उद्देश्य क्या है, इससे अधिक कुछ नहीं।
- एक निर्दोष डेवलपर के लिए
Fooक्लास में एक नया तरीका जोड़ने और गलती से enabledचेक को जोड़ने के लिए "भूल" करने का कोई तरीका नहीं है । enabledजांच व्यवहार स्वचालित रूप से किसी भी नए जोड़े विधि द्वारा प्राप्त होती है।
- यदि आपको एक और क्रॉस-कटिंग चिंता जोड़ने की आवश्यकता है, या यदि आपको
enabledचेक को बढ़ाने की आवश्यकता है , तो यह सुरक्षित रूप से और एक स्थान पर करना बहुत आसान है।
- यह अच्छा है कि आप इस AOP जैसा व्यवहार बिल्ट-इन जावा कार्यक्षमता के साथ प्राप्त कर सकते हैं। आपको कुछ अन्य ढांचे को एकीकृत करने के लिए मजबूर नहीं किया जाता है
Spring, हालांकि वे निश्चित रूप से अच्छे विकल्प भी हो सकते हैं।
निष्पक्ष होने के लिए, निम्न में से कुछ हैं:
- प्रॉक्सी कोड को लागू करने वाले कुछ कार्यान्वयन कोड बदसूरत हैं। कुछ लोग यह भी कहेंगे कि वर्ग की तात्कालिकता को रोकने के लिए आंतरिक कक्षाएं होना
FooImplबदसूरत है।
- यदि आप एक नई विधि जोड़ना चाहते हैं
Foo, तो आपको 2 स्थानों में परिवर्तन करना होगा: कार्यान्वयन वर्ग और इंटरफ़ेस। कोई बड़ी बात नहीं है, लेकिन यह अभी भी थोड़ा और काम है।
- प्रॉक्सी चालान मुफ्त नहीं हैं। एक निश्चित प्रदर्शन ओवरहेड है। हालांकि सामान्य उपयोग के लिए, यह ध्यान देने योग्य नहीं होगा। अधिक जानकारी के लिए यहाँ देखें ।
संपादित करें:
Fabian Streitel की टिप्पणी ने मुझे अपने उपरोक्त समाधान के साथ 2 परेशानियों के बारे में सोचने पर मजबूर कर दिया है, मैं मानता हूँ, मैं अपने बारे में खुश नहीं हूँ:
- मंगलाचरण हैंडलर "getEnabled" और "setEnabled" विधियों पर "सक्षम-चेक" को छोड़ने के लिए जादू के तार का उपयोग करता है। यह आसानी से टूट सकता है अगर विधि के नाम को फिर से दर्ज किया जाए।
- यदि कोई ऐसा मामला था, जिसमें नए तरीकों को जोड़ने की आवश्यकता है, जो "सक्षम-जांच" व्यवहार को प्राप्त नहीं करना चाहिए, तो डेवलपर के लिए यह गलत होना बहुत आसान हो सकता है, और बहुत कम से कम, इसका मतलब अधिक जादू जोड़ना होगा तार।
बिंदु # 1 को हल करने के लिए, और बिंदु # 2 के साथ समस्या को कम से कम करने के लिए, मैं एक एनोटेशन BypassCheck(या कुछ इसी तरह) बनाऊंगा जिसका उपयोग मैं Fooइंटरफ़ेस में उन तरीकों को चिह्नित करने के लिए कर सकता हूं जिनके लिए मैं "प्रदर्शन नहीं करना चाहता" सक्षम जांच "। इस तरह, मुझे जादू के तार की ज़रूरत नहीं है, और डेवलपर के लिए इस विशेष मामले में एक नई विधि को सही ढंग से जोड़ना बहुत आसान हो जाता है।
एनोटेशन समाधान का उपयोग करते हुए, कोड इस तरह दिखेगा:
main तरीका:
public static void main(String[] args) {
Foo foo = Foo.newFoo();
foo.setEnabled(false);
foo.bar(); // won't print anything.
foo.setEnabled(true);
foo.bar(); // prints "Executing method bar"
}
BypassCheck एनोटेशन:
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BypassCheck {
}
Foo इंटरफेस:
public interface Foo {
@BypassCheck boolean getEnabled();
@BypassCheck void setEnabled(boolean enable);
void bar();
void baz();
void bat();
// Needs Java 8 to have this convenience method here.
static Foo newFoo() {
FooFactory fooFactory = new FooFactory();
return fooFactory.makeFoo();
}
}
FooFactory वर्ग:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class FooFactory {
public Foo makeFoo() {
return (Foo) Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[]{Foo.class},
new FooInvocationHandler(new FooImpl()));
}
private static class FooImpl implements Foo {
private boolean enabled = false;
@Override
public boolean getEnabled() {
return this.enabled;
}
@Override
public void setEnabled(boolean enable) {
this.enabled = enable;
}
@Override
public void bar() {
System.out.println("Executing method bar");
}
@Override
public void baz() {
System.out.println("Executing method baz");
}
@Override
public void bat() {
System.out.println("Executing method bat");
}
}
private static class FooInvocationHandler implements InvocationHandler {
private FooImpl fooImpl;
public FooInvocationHandler(FooImpl fooImpl) {
this.fooImpl = fooImpl;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Foo.class
&& !method.isAnnotationPresent(BypassCheck.class) // no magic strings
&& !this.fooImpl.getEnabled()) {
return null;
}
return method.invoke(this.fooImpl, args);
}
}
}