আপনার লক্ষ্যের কিছু সীমাবদ্ধ রূপটি টীকা এবং ডায়নামিক প্রক্সি প্যাটার্নের সংমিশ্রণের মাধ্যমে জাভা এবং সি # তে আমার জ্ঞানের পক্ষে সম্ভব (জাভা এবং সি # তে গতিশীল প্রক্সিগুলির জন্য অন্তর্নির্মিত বাস্তবায়ন রয়েছে)।
জাভা সংস্করণ
টিকা:
@Target(ElementType.PARAMETER)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface IntRange {
int min ();
int max ();
}
প্রকৃতির দৃষ্টান্ত তৈরি করে র্যাপার শ্রেণি:
public class Wrapper {
public static Object wrap(Object obj) {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new MyInvocationHandler(obj));
}
}
ইনভোকেশনহ্যান্ডলার প্রতিটি পদ্ধতি কলটিতে বাইপাস হিসাবে পরিবেশন করছেন:
public class MyInvocationHandler implements InvocationHandler {
private Object impl;
public MyInvocationHandler(Object obj) {
this.impl = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Annotation[][] parAnnotations = method.getParameterAnnotations();
Annotation[] par = null;
for (int i = 0; i<parAnnotations.length; i++) {
par = parAnnotations[i];
if (par.length > 0) {
for (Annotation anno : par) {
if (anno.annotationType() == IntRange.class) {
IntRange range = ((IntRange) anno);
if ((int)args[i] < range.min() || (int)args[i] > range.max()) {
throw new Throwable("int-Parameter "+(i+1)+" in method \""+method.getName()+"\" must be in Range ("+range.min()+","+range.max()+")");
}
}
}
}
}
return method.invoke(impl, args);
}
}
ব্যবহারের জন্য উদাহরণ-ইন্টারফেস:
public interface Example {
public void print(@IntRange(min=0,max=100) int num);
}
প্রধান-পদ্ধতি:
Example e = new Example() {
@Override
public void print(int num) {
System.out.println(num);
}
};
e = (Example)Wrapper.wrap(e);
e.print(-1);
e.print(10);
আউটপুট:
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy0.print(Unknown Source)
at application.Main.main(Main.java:13)
Caused by: java.lang.Throwable: int-Parameter 1 in method "print" must be in Range (0,100)
at application.MyInvocationHandler.invoke(MyInvocationHandler.java:27)
... 2 more
সি শার্প -Version
টীকাগুলি (সি # তে বৈশিষ্ট্য বলে):
[AttributeUsage(AttributeTargets.Parameter)]
public class IntRange : Attribute
{
public IntRange(int min, int max)
{
Min = min;
Max = max;
}
public virtual int Min { get; private set; }
public virtual int Max { get; private set; }
}
ডায়নামিকবজেক্ট সাব-ক্লাস:
public class DynamicProxy : DynamicObject
{
readonly object _target;
public DynamicProxy(object target)
{
_target = target;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
TypeInfo clazz = (TypeInfo) _target.GetType();
MethodInfo method = clazz.GetDeclaredMethod(binder.Name);
ParameterInfo[] paramInfo = method.GetParameters();
for (int i = 0; i < paramInfo.Count(); i++)
{
IEnumerable<Attribute> attributes = paramInfo[i].GetCustomAttributes();
foreach (Attribute attr in attributes)
{
if (attr is IntRange)
{
IntRange range = attr as IntRange;
if ((int) args[i] < range.Min || (int) args[i] > range.Max)
throw new AccessViolationException("int-Parameter " + (i+1) + " in method \"" + method.Name + "\" must be in Range (" + range.Min + "," + range.Max + ")");
}
}
}
result = _target.GetType().InvokeMember(binder.Name, BindingFlags.InvokeMethod, null, _target, args);
return true;
}
}
দ্য দ্য ক্লাস:
public class ExampleClass
{
public void PrintNum([IntRange(0,100)] int num)
{
Console.WriteLine(num.ToString());
}
}
ব্যবহার:
static void Main(string[] args)
{
dynamic myObj = new DynamicProxy(new ExampleClass());
myObj.PrintNum(99);
myObj.PrintNum(-5);
}
উপসংহারে, আপনি দেখতে পাচ্ছেন যে জাভাতে কাজ করার জন্য আপনি এরকম কিছু পেতে পারেন , তবে এটি পুরোপুরি সুবিধাজনক নয়, কারণ
- প্রক্সি ক্লাসটি কেবল ইন্টারফেসের জন্য ইনস্ট্যান্ট করা যায়, অর্থাত আপনার ক্লাসটি একটি ইন্টারফেস প্রয়োগ করতে হবে
- অনুমোদিত রেঞ্জটি কেবলমাত্র ইন্টারফেস স্তরে ঘোষণা করা যেতে পারে
- পরে ব্যবহার শুরুতে অতিরিক্ত প্রচেষ্টা সহ আসে (MyInvocationHandler, প্রতিটি ইনস্ট্যান্টে মোড়ানো) যা সামান্য বোধগম্যতাও হ্রাস করে
সি # তে ডায়নামিকবজেক্ট শ্রেণীর ক্ষমতা ইন্টারফেসের সীমাবদ্ধতা সরিয়ে দেয়, যেমন আপনি সি # বাস্তবায়নে দেখছেন। দুর্ভাগ্যক্রমে, এই গতিশীল আচরণটি এক্ষেত্রে স্থিতিশীল ধরণের সুরক্ষা অপসারণ করে, তাই গতিশীল প্রক্সিটিতে কোনও পদ্ধতিতে কল অনুমোদিত কিনা তা নির্ধারণ করার জন্য রানটাইম চেকগুলি প্রয়োজনীয়।
যদি এই বিধিনিষেধগুলি আপনার পক্ষে গ্রহণযোগ্য হয়, তবে এটি আরও খননের জন্য ভিত্তি হিসাবে কাজ করতে পারে!