জাভা (অ্যান্ড্রয়েড) এ একাধিক উত্তরাধিকার


15

কোডটির যথাযথ প্রয়োগের ক্ষেত্রে আমার ধারণাগত সমস্যা রয়েছে যা মনে হয় একাধিক উত্তরাধিকারের প্রয়োজন, এটি অনেক ওও ভাষায় সমস্যা হবে না তবে প্রকল্পটি অ্যান্ড্রয়েডের জন্য হওয়ায় একাধিক জাতীয় কিছু নেই extends

আমি অনেক কাজ গুচ্ছ, এই ধরনের সহজ বিভিন্ন বেস ক্লাস, থেকে উদ্ভূত আছে Activity, TabActivity, ListActivity, ExpandableListActivity, ইত্যাদি এছাড়াও আমি কিছু কোড টুকরা যা আমি মধ্যে জায়গা দরকার onStart, onStop, onSaveInstanceState, onRestoreInstanceStateএবং অন্যান্য মান ঘটনা সব কার্যক্রম হ্যান্ডেলার।

আমার যদি সমস্ত ক্রিয়াকলাপের জন্য একক বেস শ্রেণি থাকে তবে আমি কোডটি একটি বিশেষ মধ্যবর্তী ডেরিভড শ্রেণিতে স্থাপন করতাম এবং তারপরে এটি প্রসারিত সমস্ত ক্রিয়াকলাপ তৈরি করতাম। দুর্ভাগ্যক্রমে, এটি কেস নয়, কারণ একাধিক বেস ক্লাস রয়েছে। কোডের একই অংশগুলি বেশ কয়েকটি মধ্যবর্তী ক্লাসে স্থাপন করা কোনও উপায় নয়, ইমো।

আর একটি পদ্ধতি হেল্পার অবজেক্ট তৈরি করা এবং উপরোক্ত ইভেন্টগুলির সমস্ত কল সহায়ককে প্রেরণ করা। তবে এর জন্য সহায়ক সহায়কটি অন্তর্ভুক্ত করা দরকার এবং সমস্ত হ্যান্ডলারগুলি সমস্ত মধ্যবর্তী শ্রেণিতে পুনরায় সংজ্ঞায়িত করা উচিত। সুতরাং এখানে প্রথম পদ্ধতির খুব বেশি পার্থক্য নেই - এখনও প্রচুর কোড সদৃশ।

যদি উইন্ডোজের অধীনে একই রকম পরিস্থিতি দেখা দেয় তবে আমি সাবক্লাস বেস ক্লাস ( Activityঅ্যান্ড্রয়েডের ক্লাসের সাথে "অনুরূপ" এমন কিছু) থাকতাম এবং সেখানে যথাযথ বার্তাগুলি আটকে থাকতাম (একক জায়গায়)।

এর জন্য জাভা / অ্যান্ড্রয়েডে কী করা যায়? আমি জানি যে জাভা উপকরণ ( কিছু বাস্তব উদাহরণ সহ ) এর মতো আকর্ষণীয় সরঞ্জাম রয়েছে তবে আমি জাভা গুরু নই এবং এই নির্দিষ্ট ক্ষেত্রে এটি চেষ্টা করার মতো কিনা তা নিশ্চিত নই।

আমি যদি অন্য কিছু শালীন সমাধান মিস করি তবে দয়া করে তাদের উল্লেখ করুন।

হালনাগাদ:

অ্যান্ড্রয়েডে যারা একই সমস্যা সমাধানে আগ্রহী হতে পারে তাদের জন্য আমি একটি সহজ কাজ খুঁজে পেয়েছি। অস্তিত্ব আবেদন বর্গ, যাতে অন্যান্য বিষয়গুলিও, ইন্টারফেস মধ্যে উপলব্ধ ActivityLifecycleCallbacks । এটি আমাদের ক্রিয়াকলাপের জন্য গুরুত্বপূর্ণ ইভেন্টগুলিতে কিছুটা মূল্য বা সংযোজন করার অনুমতি দেওয়ার প্রয়োজন হুবহু কাজ করে। এই পদ্ধতির একমাত্র ত্রুটিটি এটি এপিআই স্তর 14 থেকে শুরু হয়ে পাওয়া যায় যা অনেক ক্ষেত্রেই যথেষ্ট নয় (আজ এপিআই স্তর 10 এর জন্য সমর্থন একটি সাধারণ প্রয়োজন)।

উত্তর:


6

আমি আশঙ্কা করছি আপনি অ্যান্ড্রয়েড / জাভাতে কোডেডলিপি ছাড়াই আপনার ক্লাসিস্টেমটি প্রয়োগ করতে পারবেন না।

তবে আপনি যদি সংযুক্ত সাহায্যকারী অবজেক্টের সাথে বিশেষ মধ্যবর্তী ডেরিভড শ্রেণীর সংমিশ্রণ করেন তবে কোড কোডলিপি হ্রাস করতে পারেন । একে ডেকরেটার_প্যাটার্ন বলা হয় :

    class ActivityHelper {
        Activity owner;
        public ActivityHelper(Activity owner){/*...*/}
        onStart(/*...*/){/*...*/}   
    }

    public class MyTabActivityBase extends TabActivity {
        private ActivityHelper helper;
        public MyTabActivityBase(/*...*/) {
            this.helper = new ActivityHelper(this);
        }

        protected void onStart() {
            super.onStart();
            this.helper.onStart();
        }
        // the same for onStop, onSaveInstanceState, onRestoreInstanceState,...
    }

    Public class MySpecialTabActivity extends MyTabActivityBase  {
       // non helper logic goes here ....
    }

সুতরাং আপনি প্রতিটি বেস শ্রেণি একটি মধ্যবর্তী বেসক্লাস তৈরি করেন যা সহায়ককে তার কলগুলি অর্পণ করে। মধ্যবর্তী বেসস্ক্ল্যাসগুলি বেসক্লেস যেখানে তারা উত্তরাধিকারসূত্রে প্রাপ্ত তা ব্যতীত অভিন্ন।


1
হ্যাঁ, আপনাকে ধন্যবাদ. আমি জানি decordator pattern। এটি একটি সর্বশেষ অবলম্বন, যা যদিও এটি প্রদর্শন করে যে আমি কী এড়াতে পছন্দ করি - কোড নকল। আমি আপনার উত্তর গ্রহণ করব, যদি অন্য কোন অন্তর্নিহিত ধারণা ভাল হয় না। "মধ্যস্থতাকারীদের" কোডটি সাধারণীকরণের জন্য আমি কি জেনারিকগুলি ব্যবহার করতে পারি?
স্ট্যান

6

আমি মনে করি আপনি কোডের নকলের ভুল ধরণের এড়াতে চেষ্টা করছেন। আমি বিশ্বাস করি মাইকেল পালকরা এ সম্পর্কে একটি নিবন্ধ লিখেছিলেন তবে দুর্ভাগ্যক্রমে আমি এটি খুঁজে পাই না। তিনি এটিকে যেভাবে বর্ণনা করেছেন তা হ'ল আপনি আপনার কোডটিকে কমলার মতো দুটি অংশ বলে মনে করতে পারেন: রাইন্ড এবং সজ্জা। রাইন্ডটি হ'ল পদ্ধতি ঘোষণা, ক্ষেত্রের ঘোষণাপত্র, শ্রেণিবিন্যাস ইত্যাদির মতো স্টাফ etc. রুপায়ণ.

শুকিয়ে আসে, আপনি অনুরূপ এড়াতে চান সজ্জা । তবে প্রায়শই প্রক্রিয়াটিতে আপনি আরও রাইন্ড তৈরি করেন। এবং ঠিক আছে।

এখানে একটি উদাহরণ:

public void method() { //rind
    boolean foundSword = false;
    for (Item item : items)
        if (item instanceof Sword)
             foundSword = true;
    boolean foundShield = false;
    for (Item item : items)
        if (item instanceof Shield)
             founShield = true;
    if (foundSword && foundShield)
        //...
}  //rind

এটি এটিতে রিফ্যাক্টর করা যেতে পারে:

public void method() {  //rind
    if (foundSword(items) && foundShield(items))
        //...
} //rind

public boolean foundSword(items) { //rind
    return containsItemType(items, Sword.class);
} //rind

public boolean foundShield(items) { //rind
    return containsItemType(items, Shield.class);
} //rind

public boolean containsItemType(items, Class<Item> itemClass) { //rind
    for (Item item : items)
        if (item.getClass() == itemClass)
             return true;
    return false;
} //rind

আমরা এই রিফ্যাক্টরিংয়ে প্রচুর রাইন্ড যুক্ত করেছি। তবে, দ্বিতীয় উদাহরণটিতে অনেক ক্লিনার রয়েছেmethod() কম ডিআরওয়াই লঙ্ঘন সহ রয়েছে।

আপনি বলেছিলেন যে আপনি সাজসজ্জার প্যাটার্নটি এড়াতে চাই কারণ এটি কোড নকল করে। আপনি যদি সেই লিঙ্কটিতে থাকা চিত্রটি দেখেন তবে দেখবেন এটি কেবল operation()স্বাক্ষরটির সদৃশ হবে (যেমন: রাইন্ড)। operation()বাস্তবায়ন (সজ্জা) প্রতিটি বর্গ জন্য পৃথক হতে হবে। আমি মনে করি ফলস্বরূপ আপনার কোডটি ক্লিনারটি শেষ হয়ে যাবে এবং স্বল্প ডুপ্লিকেশন কম থাকবে।


3

উত্তরাধিকারের তুলনায় আপনার রচনা পছন্দ করা উচিত। .NET WCF ফ্রেমওয়ার্কের আইেক্সটেনশন " প্যাটার্ন " এর একটি দুর্দান্ত উদাহরণ । বৈজ্ঞানিকভাবে আপনার কাছে 3 টি ইন্টারফেস, এক্সটেনশন, আইেক্সটেনসিবলবজেক্ট এবং আইএক্সটেনশন কালেকশন রয়েছে। তারপরে আপনি কোনও এক্সটেনশন আইেক্সটেনশন সংগ্রহ সংস্থায় অ্যাডিগ ইয়েকশন এক্সটেনশনগুলি দ্বারা একটি আইেক্সটেনসিবল অবজেক্টের সাথে বিভিন্ন আচরণ রচনা করতে পারেন । জাভাতে এটি দেখতে কিছুটা দেখতে পাওয়া উচিত, তবে এটি নয় যে আপনি নিজের আইএক্সটেনশনক্লিকেশন বাস্তবায়ন তৈরি করতে হবে যা আইটেমগুলি যুক্ত / সরানো হচ্ছে যখন সংযুক্তি এবং বিচ্ছিন্ন পদ্ধতিগুলি কল করে। এছাড়াও নোট করুন যে আপনার এক্সটেনসিবল ক্লাসে এক্সটেনশন পয়েন্টগুলি সংজ্ঞায়িত করা আপনার উপর নির্ভর করে উদাহরণটি ইভেন্টের মতো কলব্যাক প্রক্রিয়া ব্যবহার করে:

import java.util.*;

interface IExtensionCollection<T> extends List<IExtension<T>> {
    public T getOwner();
}

interface IExtensibleObject<T> {
    IExtensionCollection<T> getExtensions();
}

interface IExtension<T> {
    void attach(T target);
    void detach(T target);
}

class ExtensionCollection<T>
    extends LinkedList<IExtension<T>>
    implements IExtensionCollection<T> {

    private T owner;
    public ExtensionCollection(T owner) { this.owner = owner; }
    public T getOwner() { return owner; }
    public boolean add(IExtension<T> e) {
        boolean result = super.add(e);
        if(result) e.attach(owner);
        return result;
    }
    // TODO override remove handler
}

interface ProcessorCallback {
    void processing(byte[] data);
    void processed(byte[] data);
}

class Processor implements IExtensibleObject<Processor> {
    private ExtensionCollection<Processor> extensions;
    private Vector<ProcessorCallback> processorCallbacks;
    public Processor() {
        extensions = new ExtensionCollection<Processor>(this);
        processorCallbacks = new Vector<ProcessorCallback>();
    }
    public IExtensionCollection<Processor> getExtensions() { return extensions; }
    public void addHandler(ProcessorCallback cb) { processorCallbacks.add(cb); }
    public void removeHandler(ProcessorCallback cb) { processorCallbacks.remove(cb); }

    public void process(byte[] data) {
        onProcessing(data);
        // do the actual processing;
        onProcessed(data);
    }
    protected void onProcessing(byte[] data) {
        for(ProcessorCallback cb : processorCallbacks) cb.processing(data);
    }
    protected void onProcessed(byte[] data) {
        for(ProcessorCallback cb : processorCallbacks) cb.processed(data);
    }
}

class ConsoleProcessor implements IExtension<Processor> {
    public ProcessorCallback console = new ProcessorCallback() {
        public void processing(byte[] data) {

        }
        public void processed(byte[] data) {
            System.out.println("processed " + data.length + " bytes...");
        }
    };
    public void attach(Processor target) {
        target.addHandler(console);
    }
    public void detach(Processor target) {
        target.removeHandler(console);
    }
}

class Main {
    public static void main(String[] args) {
        Processor processor = new Processor();
        IExtension<Processor> console = new ConsoleProcessor();
        processor.getExtensions().add(console);

        processor.process(new byte[8]);
    }
}

আপনি যদি আপনার ক্লাসের মধ্যে সাধারণ এক্সটেনশন পয়েন্টগুলি পরিচালনা করতে পরিচালনা করেন তবে এই পদ্ধতির এক্সটেনশন পুনঃব্যবহারের সুবিধা রয়েছে।


1
হতে পারে কারণ আমি। নেট ব্যবহার করি না, তবে আমি এই উত্তরটি বুঝতে খুব কষ্ট পেয়েছি। আপনি এই তিনটি ইন্টারফেস ব্যবহার করে একটি উদাহরণ যুক্ত করতে পারেন?
ড্যানিয়েল ক্যাপলান

আপনাকে ধন্যবাদ, খুব আকর্ষণীয়। তবে কেবল এক্সটেনসিবল অবজেক্টে এক্সটেনশনের কলব্যাকগুলি নিবন্ধন করা কি এত সহজ হবে না? এমন কিছু processor.addHandler(console)সরবরাহ করা যা ConsoleProcessorকলব্যাক ইন্টারফেস নিজেই প্রয়োগ করে। "এক্সটেনশন" প্যাটার্নটি মিশ্রণের মতো দেখায় visitorএবং decoratorতবে এটি কি এই ক্ষেত্রে প্রয়োজনীয়?
স্ট্যান

আপনি যদি প্রসেসরে সরাসরি এক্সটেনশানগুলি নিবন্ধভুক্ত করেন (== এক্সটেনসিবলবজেক্ট) আপনার টাইট কাপলিং রয়েছে। এখানে ধারণাটি এমন একটি এক্সটেনশন রয়েছে যা একই এক্সটেনশন পয়েন্ট সহ এক্সটেনসেবল অবজেক্টগুলির মধ্যে পুনরায় ব্যবহার করা যেতে পারে। আসলে প্যাটার্নটি মিক্সার প্যাটার্ন সিমুলেশনের মতো মোরা ।
m0sa

হুম, আমি নিশ্চিত নই যে ইন্টারফেসের মাধ্যমে বাঁধাই একটি আঁটসাঁটো মিলন। সবচেয়ে মজার বিষয় হ'ল এমনকি এক্সটেনশান প্যাটার্ন অনুসারে এক্সটেনসিবল অবজেক্ট এবং এক্সটেনশন উভয়ই একই কর্মী ইন্টারফেসের উপর নির্ভর করে ("কলব্যাক"), তাই মিলন একই রকম থাকে, ইমো। অন্য কথায়, আমি "প্রসেসরের" ওয়ার্কার ইন্টারফেসের সমর্থনের জন্য কোডিং ছাড়াই বিদ্যমান এক্সটেনশনটিকে নতুন এক্সটেনসিবল অবজেক্টে প্লাগ করতে পারি না। যদি "এক্সটেনশন পয়েন্ট" এর অর্থ আসলে কর্মী ইন্টারফেস হয় তবে আমি কোনও পার্থক্য দেখি না।
স্ট্যান

0

অ্যান্ড্রয়েড 3.0.০ থেকে শুরু করে, কোনও খণ্ড ব্যবহার করে এটি মার্জিতভাবে সমাধান করা সম্ভব । টুকরাগুলির নিজস্ব জীবনকালীন কলব্যাক রয়েছে এবং কোনও ক্রিয়াকলাপের ভিতরে এটি স্থাপন করা যেতে পারে। আমি নিশ্চিত না যদিও এটি সমস্ত ইভেন্টের জন্য কাজ করবে।

অপর একটি বিকল্প সম্পর্কে আমিও নিশ্চিত নই (কে-বি বি এর বিপরীত উপায়ে কোনও ডিকোরেটর ব্যবহার করতে পারে - গভীরতার অ্যান্ড্রয়েড জানা-কী অভাব রয়েছে): এর ActivityWrapperকলব্যাক পদ্ধতিতে আপনার সাধারণ কোড রয়েছে এমন একটি তৈরি করুন এবং তার পরে একটি মোড়ানো Activityবস্তুতে (আপনার প্রকৃত বাস্তবায়ন ক্লাস), এবং তারপরে অ্যান্ড্রয়েডের সেই মোড়ক শুরু করুন।


-3

এটি সত্য যে জাভা একাধিক-উত্তরাধিকারের অনুমতি দেয় না, তবে আপনি নিজের সামাআকিটিভিটি প্রতিটি উপ-ক্লাসের মূল ক্রিয়াকলাপকে বাড়িয়ে দিয়ে কম-বেশি এটিকে সিমুলেট করতে পারেন।

আপনার মতো কিছু থাকবে:

public class TabActivity extends Activity {
    .
    .
    .
}

2
ক্লাসগুলি ইতিমধ্যে এটি করে তবে ক্রিয়াকলাপ বেস শ্রেণিটি অ্যান্ড্রয়েড API এর অংশ এবং এটি বিকাশকারীরা পরিবর্তন করতে পারে না।
মাইকেল বর্গওয়ার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.