সংকলন-সময় মান পরামিতি সহ জাভা শ্রেণি তৈরি করা


10

এমন একটি পরিস্থিতি বিবেচনা করুন যেখানে কোনও শ্রেণি একই বুনিয়াদি আচরণ, পদ্ধতিগুলি এবং সেটারের প্রয়োগ করে তবে শ্রেণীর একাধিক বিভিন্ন সংস্করণ বিভিন্ন ব্যবহারের জন্য উপস্থিত থাকতে পারে। আমার বিশেষ ক্ষেত্রে, আমার একটি ভেক্টর রয়েছে (জ্যামিতিক ভেক্টর, একটি তালিকা নয়) এবং সেই ভেক্টর যে কোনও এন-ডাইমেনশনাল ইউক্লিডিয়ান স্পেসে প্রয়োগ করতে পারে (1 মাত্রিক, 2 মাত্রিক, ...)। এই শ্রেণি / প্রকারটি কীভাবে সংজ্ঞায়িত করা যায়?

এটি সি ++ তে সহজ হবে যেখানে শ্রেণি টেম্পলেটগুলির প্যারামিটার হিসাবে প্রকৃত মান থাকতে পারে, তবে জাভাতে আমাদের সেই বিলাসিতা নেই।

এই সমস্যাটি সমাধান করার জন্য যে দুটি পদ্ধতির বিষয়ে আমি ভাবতে পারি তা হ'ল:

  1. সংকলন সময় প্রতিটি সম্ভাব্য কেস বাস্তবায়ন।

    public interface Vector {
        public double magnitude();
    }
    
    public class Vector1 implements Vector {
        public final double x;
        public Vector1(double x) {
            this.x = x;
        }
        @Override
        public double magnitude() {
            return x;
        }
        public double getX() {
            return x;
        }
    }
    
    public class Vector2 implements Vector {
        public final double x, y;
        public Vector2(double x, double y) {
            this.x = x;
            this.y = y;
        }
        @Override
        public double magnitude() {
            return Math.sqrt(x * x + y * y);
        }
        public double getX() {
            return x;
        }
        public double getY() {
            return y;
        }
    }
    

    এই সমাধানটি অবশ্যই খুব সময় সাশ্রয়ী এবং কোডের জন্য অত্যন্ত ক্লান্তিকর। এই উদাহরণে এটি খুব খারাপ বলে মনে হচ্ছে না, তবে আমার আসল কোডে আমি ভেক্টরগুলির সাথে চারটি মাত্রা (x, y, z, এবং ডাব্লু) পর্যন্ত একাধিক বাস্তবায়নকারীগুলির সাথে কাজ করছি। আমার কাছে বর্তমানে 2 হাজারেরও বেশি লাইনের কোড রয়েছে, যদিও প্রতিটি ভেক্টরকে কেবলমাত্র 500 টি প্রয়োজন।

  2. রানটাইমে প্যারামিটার নির্দিষ্ট করে।

    public class Vector {
        private final double[] components;
        public Vector(double[] components) {
            this.components = components;
        }
        public int dimensions() {
            return components.length;
        }
        public double magnitude() {
            double sum = 0;
            for (double component : components) {
                sum += component * component;
            }
            return Math.sqrt(sum);
        }
        public double getComponent(int index) {
            return components[index];
        }
    }
    

    দুর্ভাগ্যক্রমে এই সমাধানটি কোড কর্মক্ষমতাকে আঘাত করে, পূর্ববর্তী সমাধানের চেয়ে ম্যাসিয়ার কোডের ফলাফল দেয় এবং সংকলন-সময়ে এতোটা নিরাপদ নয় (এটি সংকলন-সময়ে নিশ্চিত করা যায় না যে আপনি যে ভেক্টরটির সাথে প্রকৃতপক্ষে আচরণ করছেন এটি দ্বি-মাত্রিক, উদাহরণ স্বরূপ).

আমি বর্তমানে এক্সেন্ডে আসলে বিকাশ করছি, সুতরাং যদি কোনও এক্সটেন্ড সমাধান পাওয়া যায় তবে সেগুলিও গ্রহণযোগ্য হবে।


আপনি যেহেতু এক্সটেন্ড ব্যবহার করছেন, আপনি কি কোনও এক্সটেক্সট ডিএসএল এর প্রসঙ্গেই এটি করছেন?
Dan1701

2
কোড-জেন অ্যাপ্লিকেশনগুলির জন্য ডিএসএল দুর্দান্ত। সংক্ষেপে, আপনি একটি সামান্য ভাষার ব্যাকরণ তৈরি করেন, সেই ভাষার উদাহরণ (এই ক্ষেত্রে বিভিন্ন ভেক্টর বর্ণনা করে), এবং কিছু কোড যা কার্যকর হয় যখন কার্যকর হয় (আপনার জাভা কোড উত্পন্ন করছে)। এক্সটেক্সট সাইটে প্রচুর সংস্থান এবং উদাহরণ রয়েছে ।
ডান1701

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

1
এই দুটি ক্লাসের একই ইন্টারফেস নেই, তারা বহুকর্মী নয় তবে আপনি সেগুলি বহুবর্ষিকভাবে ব্যবহার করার চেষ্টা করছেন।
মার্টিন স্পামার

1
আপনি যদি লিনিয়ার বীজগণিত গণিত লিখছেন এবং কর্মক্ষমতা সম্পর্কে উদ্বিগ্ন হন তবে জাভা কেন। আমি এতে সমস্যা ছাড়া আর কিছুই দেখতে পাচ্ছি না।
সোপেল

উত্তর:


1

এর মতো ক্ষেত্রে আমি কোড উত্পন্ন করি।

আমি একটি জাভা অ্যাপ্লিকেশন লিখি যা আসল কোড তৈরি করে। আপনি সহজেই বিভিন্ন সংস্করণের গুচ্ছ তৈরি করতে লুপের জন্য সহজেই ব্যবহার করতে পারেন। আমি জাভাপায়েট ব্যবহার করি , যা প্রকৃত কোডটি তৈরি করতে এটি বেশ সোজা করে তোলে। তারপরে আপনি কোড তৈরি করতে আপনার বিল্ড সিস্টেমে সংহত করতে পারেন।


0

আমার অ্যাপ্লিকেশনটিতে আমার খুব অনুরূপ একটি মডেল রয়েছে এবং আমাদের সমাধানটি ছিল আপনার দ্রবণ 2 এর মতো একটি গতিশীল আকারের মানচিত্রটি কেবল রাখা।

আপনাকে কেবল জাভা অ্যারের মতো প্রাথমিক হিসাবে পারফরম্যান্স সম্পর্কে চিন্তা করার দরকার নেই। আমরা 10,000 টি সারি দ্বারা 100 টি কলামের (আবশ্যক: 100 টি মাত্রিক ভেক্টর) মাপের ম্যাট্রিক্সগুলি তৈরি করি এবং আপনার সমাধানের চেয়ে আরও জটিল ভেক্টর প্রকারের সাথে আমরা ভাল পারফরম্যান্স করেছি You আপনি ক্লাসটি সিল করার চেষ্টা করতে পারেন বা পদ্ধতিগুলি চূড়ান্ত হিসাবে চিহ্নিত করতে পারেন এটির গতি বাড়ানোর জন্য, তবে আমি মনে করি আপনি অকালে অপ্টিমাইজ করছেন।

আপনার কোডটি ভাগ করে নেওয়ার জন্য একটি বেস ক্লাস তৈরি করে আপনি কিছু কোড-সঞ্চয় (পারফরম্যান্সের মূল্যে) পেতে পারেন:

public interface Vector(){

    abstract class Abstract {           
        protected abstract double[] asArray();

        int dimensions(){ return asArray().length; }

        double magnitude(){ 
            double sum = 0;
            for (double component : asArray()) {
                sum += component * component;
            }
            return Math.sqrt(sum);
        }     

        //any additional behavior here   
    }
}

public class Scalar extends Vector.Abstract {
    private double x;

    public double getX(){
        return x;
    }

    @Override
    public double[] asArray(){
        return new double[]{x};
    }
}

public class Cartesian extends Vector.Abstract {

    public double x, y;

    public double getX(){ return x; }
    public double getY(){ return y; }

    @Override public double[] asArray(){ return new double[]{x, y}; }
}

তবে অবশ্যই আপনি যদি জাভা -8 + এ থাকেন তবে এটিকে আরও কঠোর করতে আপনি ডিফল্ট ইন্টারফেস ব্যবহার করতে পারেন:

public interface Vector{

    default public double magnitude(){
        double sum = 0;
        for (double component : asArray()) {
            sum += component * component;
        }
        return Math.sqrt(sum);
    }

    default public int dimensions(){
        return asArray().length;
    }

    default double getComponent(int index){
        return asArray()[index];
    }

    double[] asArray();

    // giving up a little bit of static-safety in exchange for 
    // runtime exceptions, we can implement the getX(), getY() 
    // etc methods here, 
    // and simply have them throw if the dimensionality is too low 
    // (you can of course do this on the abstract-class strategy as well)

    //document or use checked-exceptions to indicate that these methods throw IndexOutOfBounds exceptions (or a wrapped version)

    default public getX(){
        return getComponent(0);
    }
    default public getY(){
        return getComponent(1);
    }
    //...


    }

    //as a general rule, defaulted interfaces should assume statelessness, 
    // so you want to avoid putting mutating operations 
    // as defaulted methods on an interface, since they'll only make your life harder
}

শেষ পর্যন্ত এর বাইরে আপনি JVM- র বিকল্পগুলির বাইরে চলে যান। আপনি অবশ্যই এগুলি সি ++ এ লিখতে পারেন এবং এটিকে জেএনএ তে জেনার মতো কিছু ব্যবহার করতে পারেন - এটি দ্রুত ম্যাট্রিক্স অপারেশনের জন্য আমাদের সমাধান, যেখানে আমরা ফোর্টারান এবং ইন্টেলের এমকেএল ব্যবহার করি - তবে এটি কেবল জিনিসগুলি ধীর করে দিচ্ছে যদি আপনি কেবল নিজের ম্যাট্রিক্স সি ++ এ লিখুন এবং জাভা থেকে তার সূচক / সেটটারগুলিকে কল করুন।


আমার প্রধান উদ্বেগ পারফরম্যান্স নয়, এটি কম্পাইল-টাইম চেকিং। আমি সত্যিই এমন একটি সমাধান চাই যেখানে ভেক্টরের আকার এবং এটিতে সঞ্চালিত ক্রিয়াকলাপগুলি সংকলন সময়ে নির্ধারিত হয় (সি ++ টেম্পলেটগুলির মতো)। আপনি যদি ম্যাট্রিক্সের সাথে 1000 মাপের আকারের আকার ধারণ করতে পারেন তবে সম্ভবত আপনার সমাধানটি সবচেয়ে ভাল তবে এই ক্ষেত্রে আমি কেবল 1 - 10 আকারের ভেক্টরগুলির সাথেই কাজ করছি
পার্কার হোয়েস

আপনি যদি প্রথম বা দ্বিতীয় সমাধানের মতো কিছু ব্যবহার করেন তবে আপনি সেগুলি সাবক্ল্যাস তৈরি করতে পারেন। এখন আমি শুধু জেজেন্ডে পড়ছি, এবং এটি কোটলিনের মতো মোটামুটি মনে হচ্ছে। Kotlin সঙ্গে, আপনি করতে পারেন সম্ভবত ব্যবহার data classসহজে 10 ভেক্টর উপশ্রেণী তৈরি করতে বস্তু। জাভা দিয়ে, ধরে নিই যে আপনি আপনার কার্যকারিতা সমস্তটি বেস শ্রেণিতে টানতে পারবেন, প্রতিটি উপশ্রেণীতে 1-10 লাইন লাগবে। কেন বেস ক্লাস তৈরি হচ্ছে না?
গ্রোস্টাভ

আমি যে উদাহরণটি দিয়েছি তা বড় আকারের হয়েছে, আমার প্রকৃত কোডটিতে ভেক্টরের জন্য সংজ্ঞায়িত প্রচুর পদ্ধতি রয়েছে যেমন ভেক্টর ডট পণ্য, উপাদান-ভিত্তিক সংযোজন এবং গুণ, এবং সেটার। যদিও আমি এটি একটি বেস ক্লাস এবং আপনার asArrayপদ্ধতি ব্যবহার করে বাস্তবায়ন করতে পারি , এই বিভিন্ন পদ্ধতিগুলি সংকলনের সময় পরীক্ষা করা হবে না (আপনি একটি স্কেলার এবং কার্টেসিয়ান ভেক্টরের মধ্যে একটি বিন্দু-পণ্য সম্পাদন করতে পারেন এবং এটি সূক্ষ্ম সংকলন করবে, তবে রানটাইম ব্যর্থ হবে) ।
পার্কার হয়েস

0

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

তারপরে আপনি যদি সমাধানটিকে অন্য মাত্রায় প্রসারিত করেন তবে আপনি কেবল এনাম এবং ল্যাম্বডাকে সংশোধন করুন।


1
দয়া করে একটি সংক্ষিপ্ত কোড স্নিপেট চিত্র আপনার সমাধান সরবরাহ করুন।
তুলিনস কর্ডোভা

0

আপনার বিকল্প 2 এর উপর ভিত্তি করে, কেন কেবল এটি করবেন না? আপনি যদি কাঁচা বেস ব্যবহার রোধ করতে চান তবে আপনি এটি বিমূর্ত করতে পারেন:

class Vector2 extends Vector
{
  public Vector2(double x, double y) {
    super(new double[]{x,y});
  }

  public double getX() {
    return getComponent(0);
  }

  public double getY() {
    return getComponent(1);
  }
}

এটি আমার প্রশ্নের "পদ্ধতি 2" এর মতো। আপনার সমাধানটি তবে কমপাইল সময়ে টাইপ সুরক্ষার গ্যারান্টি দেওয়ার একটি উপায় দেয়, তবে একটি তৈরির ওভারহেড double[]এমন একটি বাস্তবায়নের তুলনায় অনাকাঙ্ক্ষিত যা কেবল 2 আদিম doubleগুলি ব্যবহার করে । এর তুলনায় ন্যূনতম উদাহরণে এটি মাইক্রোপটিমাইজেশনের মতো বলে মনে হয় তবে আরও জটিল একটি বিষয় বিবেচনা করুন যেখানে আরও বেশি মেটাডেটা জড়িত রয়েছে এবং প্রশ্নের ধরণটির স্বল্পকালীন জীবনকাল রয়েছে।
পার্কার হয়েস

1
ঠিক যেমনটি বলা হয়েছে, এটি 2 পদ্ধতির উপর ভিত্তি করে তার উত্তর সম্পর্কে গ্রুস্তভের সাথে আপনার আলোচনার ভিত্তিতে আমি অনুভূতি পেয়েছি যে আপনার উদ্বেগটি পারফরম্যান্সের সাথে নয়। আপনি কি এই ওভারহেডকে পরিমাণযুক্ত করেছেন 1 এর পরিবর্তে 2 টি বস্তু তৈরি করেছেন? সংক্ষিপ্ত জীবনকাল সম্পর্কে, আধুনিক জেভিএমগুলি এই ক্ষেত্রে অপ্টিমাইজড এবং দীর্ঘতর জীবিত সামগ্রীর চেয়ে কম জিসি ব্যয় (মূলত 0) হওয়া উচিত। আমি নিশ্চিত নই যে মেটাটাটা এটিতে কীভাবে কার্যকর হয়। এই মেটাডেটা স্কেলার বা মাত্রিক?
জিমি জেমস

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

আমি যা মনে করি আমি সত্যই সন্ধান করছিলাম সেটি ছিল আরও একটি স্বয়ংক্রিয় সমাধান যা পদ্ধতি 1 এর অনুরূপ বাইটকোড তৈরি করেছিল, যা স্ট্যান্ডার্ড জাভা বা এক্সটেন্ডে সত্যিই সম্ভব নয়। যখন আমি কাজটি শেষ করেছিলাম তখন 2 পদ্ধতিটি ব্যবহার করা হয়েছিল যেখানে এই সময়কালের সময় এই বিষয়গুলির আকারের পরামিতিগুলি গতিশীল হওয়ার প্রয়োজন ছিল এবং ক্লান্তিকরভাবে আরও দক্ষ, বিশেষায়িত প্রয়োগগুলি তৈরি করা হয়েছে যেখানে এই পরামিতিগুলি স্থির ছিল। যদি এর জীবনকাল তুলনামূলকভাবে দীর্ঘ হয় তবে Vectorবাস্তবায়নটি "ডায়নামিক" সুপারটাইপকে আরও বিশেষীকৃত বাস্তবায়ন (উদাহরণস্বরূপ Vector3) দ্বারা প্রতিস্থাপন করবে ।
পার্কার হয়েস

0

একটি ধারণা:

  1. একটি বিমূর্ত বেস শ্রেণি ভেক্টর একটি getComp घटक (i) পদ্ধতির উপর ভিত্তি করে পরিবর্তনশীল-মাত্রা বাস্তবায়ন সরবরাহ করে।
  2. ইনডিভিউয়াল সাবক্লাস ভেক্টর 1, ভেক্টর 2, ভেক্টর 3, ভেক্টর পদ্ধতিগুলিকে ওভাররাইড করে সাধারণ কেসগুলি কভার করে।
  3. সাধারণ ক্ষেত্রে একটি ডাইনভেক্টর সাবক্লাস।
  4. ভেক্টর 1, ভেক্টর 2 বা ভেক্টর 3 ফিরিয়ে আনার জন্য ঘোষিত সাধারণ ক্ষেত্রে স্থির দৈর্ঘ্যের আর্গুমেন্ট তালিকার কারখানা পদ্ধতি methods
  5. আরজিস্টের দৈর্ঘ্যের উপর নির্ভর করে ভের্টরকে ফেরত দিতে ঘোষিত একটি ভ্যার-আরগস কারখানা পদ্ধতি V

এটি আপনাকে সাধারণ ক্ষেত্রে ত্যাগ না করে সাধারণ ক্ষেত্রে এবং কিছু সংকলন-সময় সুরক্ষা (এখনও উন্নত করা যায়) ভাল কার্যকারিতা দেয়।

কোড কঙ্কাল:

public abstract class Vector {
    protected abstract int dimension();
    protected abstract double getComponent(int i);
    protected abstract void setComponent(int i, double value);

    public double magnitude() {
        double sum = 0.0;
        for (int i=0; i<dimension(); i++) {
            sum += getComponent(i) * getComponent(i);
        }
        return Math.sqrt(sum);
    }

    public void add(Vector other) {
        for (int i=0; i<dimension(); i++) {
            setComponent(i, getComponent(i) + other.getComponent(i));
        }
    }

    public static Vector1 create(double x) {
        return new Vector1(x);
    }

    public static Vector create(double... values) {
        switch(values.length) {
        case 1:
            return new Vector1(values[0]);
        default:
            return new DynVector(values);
        }

    }
}

class Vector1 extends Vector {
    private double x;

    public Vector1(double x) {
        super();
        this.x = x;
    }

    @Override
    public double magnitude() {
        return Math.abs(x);
    }

    @Override
    protected int dimension() {
        return 1;
    }

    @Override
    protected double getComponent(int i) {
        return x;
    }

    @Override
    protected void setComponent(int i, double value) {
        x = value;
    }

    @Override
    public void add(Vector other) {
        x += ((Vector1) other).x;
    }

    public void add(Vector1 other) {
        x += other.x;
    }
}

class DynVector extends Vector {
    private double[] values;
    public DynVector(double[] values) {
        this.values = values;
    }

    @Override
    protected int dimension() {
        return values.length;
    }

    @Override
    protected double getComponent(int i) {
        return values[i];
    }

    @Override
    protected void setComponent(int i, double value) {
        values[i] = value;
    }

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