আমি মার্জিত সম্পর্কে জানি না, তবে এখানে জাভা অন্তর্নির্মিত ব্যবহার করে একটি কার্যকরী বাস্তবায়ন রয়েছে 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
চেকটি বাড়ানোর প্রয়োজন হয় তবে নিরাপদে এবং এক জায়গায় এটি করা খুব সহজ।
- এটি একধরনের সুন্দর যে আপনি অন্তর্নির্মিত জাভা কার্যকারিতা সহ এই এওপি-জাতীয় আচরণ পেতে পারেন। আপনি যেমন কিছু অন্যান্য কাঠামো একীকরণ করতে বাধ্য করা হয় না
Spring
, যদিও তারা অবশ্যই ভাল বিকল্প হতে পারে।
পরিষ্কার কথা বলতে গেলে কিছুটা ডাউনসাইড হ'ল:
- প্রক্সি আমন্ত্রণগুলি পরিচালনা করে এমন কিছু বাস্তবায়ন কোড কুৎসিত। কেউ কেউ আরও বলবেন যে শ্রেণীর তাত্ক্ষণিকতা রোধ করার জন্য অভ্যন্তরীণ ক্লাসগুলি করা
FooImpl
কুশ্রী।
- আপনি যদি একটি নতুন পদ্ধতি যুক্ত করতে চান তবে
Foo
আপনাকে 2 স্পটে পরিবর্তন করতে হবে: বাস্তবায়ন শ্রেণি এবং ইন্টারফেস। বড় কথা নয়, তবে এটি এখনও কিছুটা বেশি কাজ।
- প্রক্সি অনুরোধগুলি নিখরচায় নয়। ওভারহেডের একটি নির্দিষ্ট পারফরম্যান্স রয়েছে। যদিও সাধারণ ব্যবহারের জন্য, এটি লক্ষণীয় হবে না। আরও তথ্যের জন্য এখানে দেখুন ।
সম্পাদনা করুন:
ফ্যাবিয়ান স্ট্রিটেলের মন্তব্য আমার উপরের সমাধানটির সাথে 2 টি বিরক্তি নিয়ে ভাবছে যা আমি স্বীকার করব, আমি নিজের সম্পর্কে খুশি নই:
- অনুরোধ হ্যান্ডলার "getEn सक्षम" এবং "সেট-সক্ষম" পদ্ধতিতে "সক্ষম-চেক" এড়ানোর জন্য যাদু স্ট্রিংগুলি ব্যবহার করে। যদি পদ্ধতির নামগুলি সংশোধন করা হয় তবে এটি সহজেই ভেঙে যেতে পারে।
- যদি এমন কোনও ঘটনা ঘটে থাকে যেখানে নতুন পদ্ধতি যুক্ত করার দরকার হয় যা "সক্ষম-চেক" আচরণের উত্তরাধিকার সূত্রে প্রাপ্ত না হয়, তবে বিকাশকারীদের পক্ষে এটি ভুল হওয়া খুব সহজ হতে পারে এবং খুব কমপক্ষে, এর অর্থ আরও যাদু যুক্ত করা উচিত স্ট্রিং।
# 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);
}
}
}