টাইপস্ক্রিপ্টে বিমূর্ত পদ্ধতি ঘোষণা করে


195

আমি টাইপস্ক্রিপ্টে বিমূর্ত পদ্ধতিগুলি কীভাবে সঠিকভাবে সংজ্ঞায়িত করতে পারি তা বোঝার চেষ্টা করছি:

মূল উত্তরাধিকার উদাহরণ ব্যবহার করে:

class Animal {
    constructor(public name) { }
    makeSound(input : string) : string;
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name) { super(name); }
    makeSound(input : string) : string {
        return "sssss"+input;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}

আমি পদ্ধতি মেকসাউন্ডকে কীভাবে সঠিকভাবে সংজ্ঞায়িত করতে পারি তা জানতে চাই, সুতরাং এটি টাইপ করা যায় এবং ওভাররিড করা সম্ভব।

এছাড়াও, আমি সঠিক protectedপদ্ধতিগুলি কীভাবে সংজ্ঞায়িত করব তা নিশ্চিত নই - এটি একটি কীওয়ার্ড বলে মনে হচ্ছে তবে এর কোনও প্রভাব নেই এবং কোডটি সংকলন করবে না।


4
অ্যাবস্ট্রাক্ট ক্লাস এবং পদ্ধতিগুলি এখন আসন্ন টাইপস্ক্রিপ্ট 1.6 এর একটি নতুন বৈশিষ্ট্য।
— ফ্যালকনপল

উত্তর:


284

nameসম্পত্তি হিসাবে চিহ্নিত করা হয় protected। এটি টাইপস্ক্রিপ্ট ১.৩ এ যুক্ত হয়েছিল এবং এখন দৃ firm়ভাবে প্রতিষ্ঠিত।

makeSoundপদ্ধতি হিসাবে চিহ্নিত করা হয় abstractযেমন ক্লাস হয়। আপনি Animalএখন সরাসরি সরাসরি ইনস্ট্যান্ট করতে পারবেন না , কারণ এটি বিমূর্ত। এটি টাইপস্ক্রিপ্ট 1.6 এর অংশ , যা এখন সরকারীভাবে লাইভ।

abstract class Animal {
    constructor(protected name: string) { }

    abstract makeSound(input : string) : string;

    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name: string) { super(name); }

    makeSound(input : string) : string {
        return "sssss"+input;
    }

    move() {
        alert("Slithering...");
        super.move(5);
    }
}

বিমূর্ত পদ্ধতি নকল করার পুরানো উপায় হ'ল কেউ যদি এটি ব্যবহার করে তবে একটি ত্রুটি নিক্ষেপ করা। আপনার প্রকল্পের ১.6 জমিটিতে টাইপসক্রিপ্টের আর একবার করার দরকার নেই:

class Animal {
    constructor(public name) { }
    makeSound(input : string) : string {
        throw new Error('This method is abstract');
    }
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name) { super(name); }
    makeSound(input : string) : string {
        return "sssss"+input;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}

এটি কি স্বাভাবিক আচরণ, আমি যদি কোনও পরামিতি মিস করি, কোনও পরামিতি টাইপ পরিবর্তন করি বা কোনও বিমূর্ত পদ্ধতিকে ওভাররাইড করার সময় ফেরতের প্রকার পরিবর্তন করি তবে সংক্ষেপক অভিযোগ করবে না?
— ভেটেরজ্যাক

1
এটি কোনও পরামিতি বাদ দেওয়ার জন্য বৈধ (আপনি যদি এটি ব্যবহার না করেন তবে আপনি যে মানটি পাশ করে তা উপেক্ষা করতে পারেন) এবং আপনার সাথে সামঞ্জস্যপূর্ণ ধরণের পরামিতি থাকতে পারে। আপনি যদি makeSound(input : number) : string {উপরের উদাহরণের ভিত্তিতে inputএকটি স্ট্রিং হওয়া উচিত তার উপর ভিত্তি করে একটি বিমূর্ত পদ্ধতি বাস্তবায়নের চেষ্টা করেন তবে আপনি একটি ত্রুটি পাবেন । Type 'string' is not assignable to type 'number'.।
— ফেন্টন

19

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

/**
 * The interface defines all abstract methods and extends the concrete base class
 */
interface IAnimal extends Animal {
    speak() : void;
}

/**
 * The abstract base class only defines concrete methods & properties.
 */
class Animal {

    private _impl : IAnimal;

    public name : string;

    /**
     * Here comes the clever part: by letting the constructor take an 
     * implementation of IAnimal as argument Animal cannot be instantiated
     * without a valid implementation of the abstract methods.
     */
    constructor(impl : IAnimal, name : string) {
        this.name = name;
        this._impl = impl;

        // The `impl` object can be used to delegate functionality to the
        // implementation class.
        console.log(this.name + " is born!");
        this._impl.speak();
    }
}

class Dog extends Animal implements IAnimal {
    constructor(name : string) {
        // The child class simply passes itself to Animal
        super(this, name);
    }

    public speak() {
        console.log("bark");
    }
}

var dog = new Dog("Bob");
dog.speak(); //logs "bark"
console.log(dog instanceof Dog); //true
console.log(dog instanceof Animal); //true
console.log(dog.name); //"Bob"

যেহেতু Animalশ্রেণীর প্রয়োগের প্রয়োজন হয় বিমূর্ত পদ্ধতিগুলির বৈধ বাস্তবায়ন না করে IAnimalধরণের একটি অবজেক্ট তৈরি করা অসম্ভব Animal। নোট করুন যে বহুকর্ম কাজ করার জন্য আপনার উদাহরণগুলি প্রায় পাস করতে হবে IAnimal, না Animal। উদাহরণ:

//This works
function letTheIAnimalSpeak(animal: IAnimal) {
    console.log(animal.name + " says:");
    animal.speak();
}
//This doesn't ("The property 'speak' does not exist on value of type 'Animal')
function letTheAnimalSpeak(animal: Animal) {
    console.log(animal.name + " says:");
    animal.speak();
}

এরিক্স উত্তরের সাথে এখানে মূল পার্থক্য হ'ল "বিমূর্ত" বেস শ্রেণীর জন্য ইন্টারফেসের একটি প্রয়োগকরণ প্রয়োজন এবং এটি নিজস্বভাবে ইনস্ট্যান্ট করা যায় না।


1
কমপক্ষে আমার জন্য টাইপসক্রিপ্ট ভি 1 দিয়ে - আমি কোনও কনস্ট্রাক্টরের কাছ থেকে সুপারিতে যাওয়ার জন্য 'এটি' উল্লেখ করতে পারি না। থটস?
— কায়রান বেন্টন

আপনি সংকলকটির সঠিক সংস্করণটি ব্যবহার করেন এবং আপনি কোন ত্রুটি পেয়েছেন? tsc 1.0.1 উপরের স্নিপেটগুলি পুরোপুরি সূক্ষ্মভাবে সংকলন করে।
— টিদো

'এই' কীওয়ার্ডটি সুপার () এ অনুমোদিত নয়। তোমার দর্শন লগ করা টিএসসি 1.0.3 ব্যবহার
— Zasz

এটা বেশ বিজোড়। আপনি কি সি এল এল সংকলক বা ভিজ্যুয়াল স্টুডিও ব্যবহার করেন?
— টিডো

আমিও সুপার () কলটিতে "এটি" ব্যবহার করতে পারি না। সন্তানের বাস্তবায়নের জন্য পিতামাতার সদস্য নির্ধারণের জন্য আমি ঠিক পরে এটি ব্যবহার করতে পারি তবে এটি বিমূর্ত শ্রেণীর সম্প্রসারণকে কার্যকর করে না। আমি প্যালান্টিরের ইলিস্প টাইপস্ক্রিপ্ট প্লাগইন ব্যবহার করছি, v1.0.1। আমি লক্ষ্য করেছি যে সুপার (এটি) টাইপস্ক্রিপ্টঅং.আর / প্লেগ্রাউন্ডে ভাল কাজ করে ।
— এরিক

2

আমি বিশ্বাস করি যে ইন্টারফেস এবং বেস ক্লাসগুলির সংমিশ্রণটি ব্যবহার করা আপনার পক্ষে কাজ করতে পারে। এটি সংকলনের সময় আচরণগত প্রয়োজনীয়তা প্রয়োগ করবে (rq_ পোস্ট "নীচে" উপরের পোস্টকে বোঝায়, যা এটি নয়)।

ইন্টারফেসটি এমন আচরণগত এপিআই সেট করে যা বেস ক্লাসে পূরণ হয় না। আপনি ইন্টারফেসে সংজ্ঞায়িত পদ্ধতিগুলিতে কল করতে বেস ক্লাসের পদ্ধতিগুলি সেট করতে সক্ষম হবেন না (কারণ আপনি সেই আচরণগুলি সংজ্ঞায়িত না করে বেস শ্রেণিতে সেই ইন্টারফেসটি প্রয়োগ করতে সক্ষম হবেন না)। পিতা-মাতার মধ্যে ইন্টারফেসের পদ্ধতিগুলি কল করার জন্য কেউ নিরাপদ কৌশল নিয়ে আসতে পারেন ।

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

এটি আপনার জন্য কাজ করে কিনা তা এখানে আটকান: http://www.tyypecriptlang.org/Playground/

// The behavioral interface also needs to extend base for substitutability
interface AbstractAnimal extends BaseAnimal {
    // encapsulates animal behaviors that must be implemented
    makeSound(input : string): string;
}

class BaseAnimal {
    constructor(public name) { }

    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

// If concrete class doesn't extend both, it cannot use super methods.
class Snake extends BaseAnimal implements AbstractAnimal {
    constructor(name) { super(name); }
    makeSound(input : string): string {
        var utterance = "sssss"+input;
        alert(utterance);
        return utterance;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}

var longMover = new Snake("windy man");

longMover.makeSound("...am I nothing?");
longMover.move();

var fulture = new BaseAnimal("bob fossil");
// compile error on makeSound() because it is not defined.
// fulture.makeSound("you know, like a...")
fulture.move(1);

নীচে লিঙ্কিত হিসাবে আমি ফ্রিস্টওয়ান ক্যাম্পেনের উত্তর জুড়ে এসেছি। তিনি বলেন যে বিমূর্ত শ্রেণিগুলি একটি অ্যান্টি-প্যাটার্ন, এবং পরামর্শ দেয় যে একটি ইনস্ট্যান্টিয়েট বেস 'অ্যাবস্ট্রাক্ট' ক্লাস প্রয়োগকারী শ্রেণীর ইনজেকশন উদাহরণ ব্যবহার করে। এটি ন্যায়সঙ্গত, তবে পাল্টা যুক্তি রয়েছে। নিজের জন্য পড়ুন: https://typescript.codeplex.com/discussion/449920

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

export class OntologyConceptFilter extends FilterWidget.FilterWidget<ConceptGraph.Node, ConceptGraph.Link> implements FilterWidget.IFilterWidget<ConceptGraph.Node, ConceptGraph.Link> {

    subMenuTitle = "Ontologies Rendered"; // overload or overshadow?

    constructor(
        public conceptGraph: ConceptGraph.ConceptGraph,
        graphView: PathToRoot.ConceptPathsToRoot,
        implementation: FilterWidget.IFilterWidget<ConceptGraph.Node, ConceptGraph.Link>
        ){
        super(graphView);
        this.implementation = this;
    }
}

এবং

export class FilterWidget<N extends GraphView.BaseNode, L extends GraphView.BaseLink<GraphView.BaseNode>> {

    public implementation: IFilterWidget<N, L>

    filterContainer: JQuery;

    public subMenuTitle : string; // Given value in children

    constructor(
        public graphView: GraphView.GraphView<N, L>
        ){

    }

    doStuff(node: N){
        this.implementation.generateStuff(thing);
    }

}

export interface IFilterWidget<N extends GraphView.BaseNode, L extends GraphView.BaseLink<GraphView.BaseNode>> extends FilterWidget<N, L> {

    generateStuff(node: N): string;

}

1

আমি বেস ক্লাসে একটি ব্যতিক্রম ছুঁড়তে ব্যবহার করি।

protected abstractMethod() {
    throw new Error("abstractMethod not implemented");
}

তারপরে আপনাকে সাব-ক্লাসে প্রয়োগ করতে হবে। কনসটি হ'ল কোনও বিল্ড ত্রুটি নেই, তবে রানটাইম। উপকারিতাটি হ'ল আপনি সুপার ক্লাস থেকে এই পদ্ধতিটি কল করতে পারেন, ধরে নিই যে এটি কার্যকর হবে :)

আছে HTH!

মিল্টন


-20

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

এছাড়াও, উপরের উদাহরণটি কেবল রান টাইমে এই প্রয়োগকারীকে সরবরাহ করবে, সংকলনের সময় নয়, আপনি জাভা / সি # তে প্রত্যাশা করবেন।


4
আমি দেখতে পাচ্ছি আপনি কোথা থেকে এসেছেন তবে আমি শ্রদ্ধার সাথে একমত নই। কোনও ভাষা যদি কিছু প্রয়োগ করে তবে এটিকে নিজেই পুনরায় প্রয়োগ করা খারাপ। তবে আপনার যদি কিছু না থাকে, তবে নিজেকে কোনওভাবে এটি বাস্তবায়ন করা ছাড়া আপনার কোনও বিকল্প নেই। অবশ্যই, আপনি রান-টাইম হওয়া পর্যন্ত সমস্যাগুলি দেখতে পাবেন না, তবে প্রথমবার যখন কোনও কিছু পরীক্ষা করার জন্য ব্যতিক্রম ছুঁড়ে দেওয়া আপনাকে জানায় যে আপনি খুব শীঘ্রই বোকা বানিয়ে ফেলেছেন। এটি অবশ্যই আদর্শ নয় - এজন্য আইএমও, টাইপসক্রিপ্টটির বিমূর্ত শ্রেণির সমর্থন প্রয়োজন needs যতক্ষণ না এটি হয় ...
— ম্যাভারিক

আমার ইচ্ছা ছিল জাভাস্ক্রিপ্টের ক্লাস, টাইপ অনুমান, স্ট্যাটিক টাইপিং এবং ইন্টারফেস রয়েছে এবং অনুমান করুন, টাইপসক্রিপ্টটির কি আছে? এটি অ্যাবস্ট্রাক্ট পদ্ধতির জন্য একই হবে, সংকলকটি কেবল এটি পরীক্ষা করতে হবে যে বিমূর্ত শ্রেণির প্রসারিত যে কোনও শ্রেণি বিমূর্ত পদ্ধতি প্রয়োগ করে, যেমন এটি ইতিমধ্যে ইন্টারফেসের জন্য করে থাকে (একটি ইন্টারফেস মূলত কেবল বিমূর্ত
— পদ্ধতিযুক্ত

1
আমি এখানে @rq_ এর সাথে একমত হতে চাই। বিমূর্ত পদ্ধতিগুলির বিষয়বস্তু হ'ল সংকলন সময় যাচাইকরণ যা প্রোগ্রামটি কোনও অবৈধ অবস্থায় যেতে পারে না। প্রস্তাবিত সমাধানগুলি আপনাকে রানটাইম চেক দেয় যার অর্থ আপনার প্রোগ্রামটি যখন চালিত হয় আপনি নিশ্চিত হতে পারবেন না যে এটি কোনও বৈধ অবস্থায় রয়েছে। এর অর্থ হল যে পদ্ধতিটি বাস্তবায়িত হয়নি এমন অনুমানের অধীনে আপনার পরিচালনা করা উচিত এবং সেই অনুসারে রক্ষা করুন। আপনার বিমূর্ত পদ্ধতি রয়েছে বলে নিজেকে মিথ্যা বলা কেবল অপ্রত্যাশিত রানটাইম আচরণের দ্বারা দংশন করতে বলছে।
— মাইকা জোল্টু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.