আমি এক্সটেনশন পদ্ধতিটি ব্যবহার করে সি # তে যেমন বস্তুর তালিকায় একটি কার্যকারিতা বাস্তবায়ন করতে দেখছি।
এটার মতো কিছু:
List<DataObject> list;
// ... List initialization.
list.getData(id);
আমি জাভাতে এটি কীভাবে করব?
আমি এক্সটেনশন পদ্ধতিটি ব্যবহার করে সি # তে যেমন বস্তুর তালিকায় একটি কার্যকারিতা বাস্তবায়ন করতে দেখছি।
এটার মতো কিছু:
List<DataObject> list;
// ... List initialization.
list.getData(id);
আমি জাভাতে এটি কীভাবে করব?
উত্তর:
জাভা এক্সটেনশন পদ্ধতি সমর্থন করে না।
পরিবর্তে, আপনি একটি নিয়মিত স্ট্যাটিক পদ্ধতি তৈরি করতে পারেন, বা আপনার নিজের ক্লাস লিখতে পারেন।
এক্সটেনশন পদ্ধতিগুলি কেবল স্থিতিশীল পদ্ধতি নয় এবং কেবল সুবিধাযুক্ত সিনট্যাক্স চিনির নয়, বাস্তবে এগুলি বেশ শক্তিশালী সরঞ্জাম। প্রধান জিনিস হ'ল বিভিন্ন জেনেরিকের পরামিতিগুলির ইনস্ট্যান্টেশনের উপর ভিত্তি করে বিভিন্ন পদ্ধতিকে ওভাররাইড করার ক্ষমতা রয়েছে। এটি হাস্কেলের ধরণের শ্রেণীর মতো এবং বাস্তবে দেখে মনে হচ্ছে যে তারা সি # এর মনড (যেমন লিনকিউ) সমর্থন করার জন্য সি # তে রয়েছে। এমনকি লিনকিউ সিনট্যাক্স বাদ দিচ্ছি, আমি এখনও জাভাতে অনুরূপ ইন্টারফেস প্রয়োগ করার কোনও উপায় জানি না।
এবং আমি মনে করি না জাভাতে জেনেরিকের পরামিতিগুলির ধরণের ক্ষয়ের শব্দার্থক কারণে এটি জাভাতে প্রয়োগ করা সম্ভব is
প্রজেক্ট লম্বোক একটি টীকা সরবরাহ করে @ExtensionMethod
যা আপনি যে কার্যকারিতা জিজ্ঞাসা করছেন তা অর্জন করতে ব্যবহার করা যেতে পারে।
java.lang.String
প্রযুক্তিগতভাবে সি # এক্সটেনশনের জাভাতে কোনও সমমান নেই। আপনি যদি ক্লিনার কোড এবং রক্ষণাবেক্ষণের জন্য এই জাতীয় ফাংশনগুলি প্রয়োগ করতে চান তবে আপনাকে ম্যানিফোল্ড ফ্রেমওয়ার্কটি ব্যবহার করতে হবে।
package extensions.java.lang.String;
import manifold.ext.api.*;
@Extension
public class MyStringExtension {
public static void print(@This String thiz) {
System.out.println(thiz);
}
@Extension
public static String lineSeparator() {
return System.lineSeparator();
}
}
ম্যানিফোল্ড সি # স্টাইল এক্সটেনশন পদ্ধতি এবং অন্যান্য বেশ কয়েকটি বৈশিষ্ট্য সহ জাভা সরবরাহ করে। অন্যান্য সরঞ্জামগুলির থেকে পৃথক, ম্যানিফোল্ডের কোনও সীমাবদ্ধতা নেই এবং জেনেরিকস, ল্যাম্বডাস, আইডিই ইত্যাদির সমস্যায় ভুগছেন না ম্যানিফোল্ড আরও কয়েকটি বৈশিষ্ট্য সরবরাহ করে যেমন এফ # স্টাইলের কাস্টম প্রকার , টাইপস্ক্রিপ্ট-স্টাইলের কাঠামোগত ইন্টারফেস এবং জাভাস্ক্রিপ্ট-শৈলীর সম্প্রসারণ প্রকার ।
অতিরিক্তভাবে, ইন্টেলিজি ম্যানিফোল্ড প্লাগইনটির মাধ্যমে ম্যানিফোল্ডের জন্য ব্যাপক সমর্থন সরবরাহ করে ।
ম্যানিফোল্ড গিথুব এ উপলব্ধ একটি ওপেন সোর্স প্রকল্প ।
অন্য বিকল্পটি হ'ল গুগল-পেয়ারা লাইব্রেরি থেকে ফরওয়ার্ডিং এক্সএক্সএক্স ক্লাস ব্যবহার করা ।
জাভাতে এ জাতীয় বৈশিষ্ট্য নেই। পরিবর্তে আপনি হয় আপনার তালিকা প্রয়োগের নিয়মিত সাবক্লাস তৈরি করতে পারেন বা বেনামে অভ্যন্তর শ্রেণি তৈরি করতে পারেন:
List<String> list = new ArrayList<String>() {
public String getData() {
return ""; // add your implementation here.
}
};
সমস্যাটি এই পদ্ধতিটি কল করা। আপনি এটি "জায়গায়" করতে পারেন:
new ArrayList<String>() {
public String getData() {
return ""; // add your implementation here.
}
}.getData();
মনে হচ্ছে কিছু ছোট সুযোগ যে ডিফেন্ডার পদ্ধতি (অর্থাত ডিফল্ট পদ্ধতি) জাভা 8. তবে সেটিকে করা হতে পারে, যতটা আমি তাদের বোঝেনা, সবাই শুধু অনুমতি মত লেখক একটি এরinterface
ব্যাপকভাবে এটি প্রসারিত, না নির্বিচারে ব্যবহারকারীদের।
ডিফেন্ডার পদ্ধতিগুলি + ইন্টারফেস ইঞ্জেকশনটি তখন সি #-স্টাইল এক্সটেনশন পদ্ধতিগুলিকে সম্পূর্ণরূপে প্রয়োগ করতে সক্ষম হবে, তবে এএএএফআইএসস, ইন্টারফেস ইঞ্জেকশনটি এখনও জাভা 8 রোড-ম্যাপে নেই।
এই প্রশ্নে পার্টিতে দেরি করে ফেলুন তবে কারও পক্ষে এটি দরকারী মনে হলে আমি কেবল একটি সাবক্লাস তৈরি করেছি:
public class ArrayList2<T> extends ArrayList<T>
{
private static final long serialVersionUID = 1L;
public T getLast()
{
if (this.isEmpty())
{
return null;
}
else
{
return this.get(this.size() - 1);
}
}
}
জাভা ৮-এর পরে উপলব্ধ ডিফল্ট পদ্ধতি প্রয়োগের মাধ্যমে আমরা জাভাতে সি # এক্সটেনশন পদ্ধতির প্রয়োগের অনুকরণ করতে পারি We আমরা একটি ইন্টারফেসটি সংজ্ঞায়িত করে শুরু করি যা আমাদের বেস () পদ্ধতির মাধ্যমে সাপোর্ট অবজেক্টে অ্যাক্সেসের অনুমতি দেবে:
public interface Extension<T> {
default T base() {
return null;
}
}
ইন্টারফেসের রাষ্ট্র থাকতে পারে না বলে আমরা নালাগুলি ফিরে আসি তবে এটি প্রক্সি দিয়ে পরে ঠিক করতে হবে।
এক্সটেনশনের বিকাশকারীকে এক্সটেনশন পদ্ধতিযুক্ত একটি নতুন ইন্টারফেস দ্বারা এই ইন্টারফেসটি প্রসারিত করতে হবে। ধরা যাক আমরা তালিকা ইন্টারফেসে প্রতিটি গ্রাহককে যুক্ত করতে চাই:
public interface ListExtension<T> extends Extension<List<T>> {
default void foreach(Consumer<T> consumer) {
for (T item : base()) {
consumer.accept(item);
}
}
}
যেহেতু আমরা এক্সটেনশন ইন্টারফেসটি প্রসারিত করি, আমরা আমাদের সংযুক্ত সমর্থন আইটেমটি অ্যাক্সেস করতে আমাদের এক্সটেনশন পদ্ধতির অভ্যন্তরে বেস () পদ্ধতিটি কল করতে পারি।
এক্সটেনশন ইন্টারফেসটির অবশ্যই একটি ফ্যাক্টরি পদ্ধতি থাকতে হবে যা প্রদত্ত সহায়তা সামগ্রীর এক্সটেনশন তৈরি করবে:
public interface Extension<T> {
...
static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
if (type.isInterface()) {
ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
List<Class<?>> interfaces = new ArrayList<Class<?>>();
interfaces.add(type);
Class<?> baseType = type.getSuperclass();
while (baseType != null && baseType.isInterface()) {
interfaces.add(baseType);
baseType = baseType.getSuperclass();
}
Object proxy = Proxy.newProxyInstance(
Extension.class.getClassLoader(),
interfaces.toArray(new Class<?>[interfaces.size()]),
handler);
return type.cast(proxy);
} else {
return null;
}
}
}
আমরা একটি প্রক্সি তৈরি করি যা এক্সটেনশন ইন্টারফেস এবং সহায়তা ইন্টারফেসের ধরণের দ্বারা প্রয়োগ করা সমস্ত ইন্টারফেস কার্যকর করে। প্রক্সিটিতে দেওয়া ইনভোকেশন হ্যান্ডলারটি "বেস" পদ্ধতি ব্যতীত সমস্ত কলগুলি সমর্থন অবজেক্টে প্রেরণ করবে, যা সমর্থন অবজেক্টটি ফেরত পাঠাতে হবে, অন্যথায় এর ডিফল্ট বাস্তবায়ন বাতিল হয়ে যাচ্ছে:
public class ExtensionHandler<T> implements InvocationHandler {
private T instance;
private ExtensionHandler(T instance) {
this.instance = instance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("base".equals(method.getName())
&& method.getParameterCount() == 0) {
return instance;
} else {
Class<?> type = method.getDeclaringClass();
MethodHandles.Lookup lookup = MethodHandles.lookup()
.in(type);
Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
makeFieldModifiable(allowedModesField);
allowedModesField.set(lookup, -1);
return lookup
.unreflectSpecial(method, type)
.bindTo(proxy)
.invokeWithArguments(args);
}
}
private static void makeFieldModifiable(Field field) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField
.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
}
তারপরে, আমরা সমর্থন অবজেক্টটিতে এক্সটেনশন পদ্ধতিযুক্ত ইন্টারফেস সংযুক্ত করতে এক্সটেনশন.ক্রেট () পদ্ধতিটি ব্যবহার করতে পারি। ফলাফলটি এমন একটি অবজেক্ট যা এক্সটেনশন ইন্টারফেসে কাস্ট করা যায় যার দ্বারা আমরা এখনও বেস () পদ্ধতিতে কল করে সমর্থন অবজেক্টটি অ্যাক্সেস করতে পারি। এক্সটেনশন ইন্টারফেসে রেফারেন্সটি কাস্ট করা পরে, আমরা এখন নিরাপদে সেই এক্সটেনশন পদ্ধতিগুলিতে কল করতে পারি যা সহায়তা অবজেক্টে অ্যাক্সেস রাখতে পারে, যাতে এখন আমরা বিদ্যমান অবজেক্টের সাথে নতুন পদ্ধতি সংযুক্ত করতে পারি, তবে তার সংজ্ঞায়িত ধরণের সাথে নয়:
public class Program {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
ListExtension<String> listExtension = Extension.create(ListExtension.class, list);
listExtension.foreach(System.out::println);
}
}
সুতরাং, এটি এমন একটি উপায় যা আমরা জাভাতে নতুন চুক্তি যুক্ত করে তাদের প্রসারিত করার ক্ষমতা অনুকরণ করতে পারি যা আমাদের প্রদত্ত বস্তুগুলিতে অতিরিক্ত পদ্ধতি কল করার অনুমতি দেয়।
নীচে আপনি এক্সটেনশন ইন্টারফেসের কোডটি পেতে পারেন:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public interface Extension<T> {
public class ExtensionHandler<T> implements InvocationHandler {
private T instance;
private ExtensionHandler(T instance) {
this.instance = instance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("base".equals(method.getName())
&& method.getParameterCount() == 0) {
return instance;
} else {
Class<?> type = method.getDeclaringClass();
MethodHandles.Lookup lookup = MethodHandles.lookup()
.in(type);
Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
makeFieldModifiable(allowedModesField);
allowedModesField.set(lookup, -1);
return lookup
.unreflectSpecial(method, type)
.bindTo(proxy)
.invokeWithArguments(args);
}
}
private static void makeFieldModifiable(Field field) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
}
default T base() {
return null;
}
static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
if (type.isInterface()) {
ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
List<Class<?>> interfaces = new ArrayList<Class<?>>();
interfaces.add(type);
Class<?> baseType = type.getSuperclass();
while (baseType != null && baseType.isInterface()) {
interfaces.add(baseType);
baseType = baseType.getSuperclass();
}
Object proxy = Proxy.newProxyInstance(
Extension.class.getClassLoader(),
interfaces.toArray(new Class<?>[interfaces.size()]),
handler);
return type.cast(proxy);
} else {
return null;
}
}
}
একটি সাজসজ্জার বস্তু ভিত্তিক নকশা প্যাটার্ন ব্যবহার করা যেতে পারে । জাভাটির স্ট্যান্ডার্ড লাইব্রেরিতে এই প্যাটার্নটির ব্যবহারের উদাহরণ হ'ল ডেটাআউটপুট স্ট্রিম ।
একটি তালিকার কার্যকারিতা বৃদ্ধির জন্য এখানে কিছু কোড রয়েছে:
public class ListDecorator<E> implements List<E>
{
public final List<E> wrapee;
public ListDecorator(List<E> wrapee)
{
this.wrapee = wrapee;
}
// implementation of all the list's methods here...
public <R> ListDecorator<R> map(Transform<E,R> transformer)
{
ArrayList<R> result = new ArrayList<R>(size());
for (E element : this)
{
R transformed = transformer.transform(element);
result.add(transformed);
}
return new ListDecorator<R>(result);
}
}
PS আমি একটি বড় ফ্যান Kotlin । এটিতে এক্সটেনশন পদ্ধতি রয়েছে এবং এটি জেভিএম-তেও চালায়।
আপনি কালেকশন ইন্টারফেসটি প্রয়োগ করে এবং জাভা সংগ্রহের জন্য উদাহরণ যোগ করে (আরই) এর মাধ্যমে এক্সটেনশন / সহায়ক পদ্ধতি তৈরি করতে পারেন:
public class RockCollection<T extends Comparable<T>> implements Collection<T> {
private Collection<T> _list = new ArrayList<T>();
//###########Custom extension methods###########
public T doSomething() {
//do some stuff
return _list
}
//proper examples
public T find(Predicate<T> predicate) {
return _list.stream()
.filter(predicate)
.findFirst()
.get();
}
public List<T> findAll(Predicate<T> predicate) {
return _list.stream()
.filter(predicate)
.collect(Collectors.<T>toList());
}
public String join(String joiner) {
StringBuilder aggregate = new StringBuilder("");
_list.forEach( item ->
aggregate.append(item.toString() + joiner)
);
return aggregate.toString().substring(0, aggregate.length() - 1);
}
public List<T> reverse() {
List<T> listToReverse = (List<T>)_list;
Collections.reverse(listToReverse);
return listToReverse;
}
public List<T> sort(Comparator<T> sortComparer) {
List<T> listToReverse = (List<T>)_list;
Collections.sort(listToReverse, sortComparer);
return listToReverse;
}
public int sum() {
List<T> list = (List<T>)_list;
int total = 0;
for (T aList : list) {
total += Integer.parseInt(aList.toString());
}
return total;
}
public List<T> minus(RockCollection<T> listToMinus) {
List<T> list = (List<T>)_list;
int total = 0;
listToMinus.forEach(list::remove);
return list;
}
public Double average() {
List<T> list = (List<T>)_list;
Double total = 0.0;
for (T aList : list) {
total += Double.parseDouble(aList.toString());
}
return total / list.size();
}
public T first() {
return _list.stream().findFirst().get();
//.collect(Collectors.<T>toList());
}
public T last() {
List<T> list = (List<T>)_list;
return list.get(_list.size() - 1);
}
//##############################################
//Re-implement existing methods
@Override
public int size() {
return _list.size();
}
@Override
public boolean isEmpty() {
return _list == null || _list.size() == 0;
}
Java
8 এখন ডিফল্ট পদ্ধতিগুলি সমর্থন করে যা C#
এর এক্সটেনশন পদ্ধতির অনুরূপ ।