ধরণ: দুই শ্রেণি কিভাবে বাড়ানো যায়?


90

আমি আমার সময় বাঁচাতে এবং ক্লাসে PIXI ক্লাসগুলি (একটি 2 ডি ওয়েবজিএল রেন্ডারির ​​পাঠাগার) প্রসারিত করার জন্য সাধারণ কোডটি পুনরায় ব্যবহার করতে চাই।

অবজেক্ট ইন্টারফেস:

module Game.Core {
    export interface IObject {}

    export interface IManagedObject extends IObject{
        getKeyInManager(key: string): string;
        setKeyInManager(key: string): IObject;
    }
}

আমার সমস্যাটি হ'ল কোডটি ভিতরে রয়েছে getKeyInManagerএবং setKeyInManagerএটি পরিবর্তন হবে না এবং আমি এটি পুনরায় ব্যবহার করতে চাই, এটির সদৃশ করতে চাই না, এখানে বাস্তবায়নটি দেওয়া হচ্ছে:

export class ObjectThatShouldAlsoBeExtended{
    private _keyInManager: string;

    public getKeyInManager(key: string): string{
        return this._keyInManager;
    }

    public setKeyInManager(key: string): DisplayObject{
        this._keyInManager = key;
        return this;
    }
}

আমি যা করতে চাই তা হ'ল স্বয়ংক্রিয়ভাবে অ্যা-এর মাধ্যমে Manager.add()ম্যানেজারে ব্যবহৃত কীটি বস্তুর ভিতরে থাকা অবজেক্টটির নিজস্ব বৈশিষ্ট্যে রেফারেন্স করতে _keyInManager

সুতরাং, আসুন একটি টেক্সচার সহ একটি উদাহরণ নেওয়া যাক। এখানে যায়TextureManager

module Game.Managers {
    export class TextureManager extends Game.Managers.Manager {

        public createFromLocalImage(name: string, relativePath: string): Game.Core.Texture{
            return this.add(name, Game.Core.Texture.fromImage("/" + relativePath)).get(name);
        }
    }
}

যখন আমি করি this.add(), আমি চাই যে Game.Managers.Manager add()পদ্ধতিটি এমন একটি পদ্ধতি কল করতে পারে যা প্রত্যাবর্তিত অবজেক্টে উপস্থিত থাকবে Game.Core.Texture.fromImage("/" + relativePath)। এই বস্তুটি, এই ক্ষেত্রে একটি হতে হবে Texture:

module Game.Core {
    // I must extends PIXI.Texture, but I need to inject the methods in IManagedObject.
    export class Texture extends PIXI.Texture {

    }
}

আমি জানি এটি IManagedObjectএকটি ইন্টারফেস এবং বাস্তবায়ন ধারণ করতে পারে না, তবে আমার ক্লাসের ObjectThatShouldAlsoBeExtendedভিতরে ক্লাসটি ইনজেক্ট করতে কী লিখতে হবে তা আমি জানি না Texture। জেনে একই প্রক্রিয়া জন্য প্রয়োজন হতে হবে Sprite, TilingSprite, Layerএবং আরো।

আমার এখানে অভিজ্ঞ টাইপসক্রিপ্ট প্রতিক্রিয়া / পরামর্শ প্রয়োজন, এটি করা অবশ্যই সম্ভব হবে, তবে একাধিক প্রসার দ্বারা নয় যেহেতু এই সময়ে কেবল একটিই সম্ভব, আমি অন্য কোনও সমাধান খুঁজে পাইনি।


7
একটি টিপ, যখনই আমি একাধিক উত্তরাধিকারের সমস্যার মুখোমুখি হই, আমি কাজটি করব কিনা তা দেখার জন্য আমি নিজেকে "উত্তরাধিকারের চেয়ে বেশি রচনাটির পক্ষপাতী" মনে করে মনে করিয়ে দেওয়ার চেষ্টা করি।
বুদবুদ

4
রাজি। 2 বছর আগে সেভাবে ভাবছিলাম না;)
ভাদোরকোয়েস্ট

6
@ বুবলিং কীভাবে উত্তরাধিকারের উপরে রচনাটির পক্ষপাতী হবে এখানে?
Seanny123

উত্তর:


97

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

টাইপস্ক্রিপ্ট মিক্সিন সম্পর্কিত আরও তথ্য

আমি মনে করি আপনি এই কৌশলটি আপনার গেমের বিভিন্ন শ্রেণীর মধ্যে সাধারণ উপাদান ভাগ করতে এবং আপনার গেমের একটি একক শ্রেণীর থেকে এই উপাদানগুলির অনেকগুলি পুনরায় ব্যবহার করতে পারেন:

এখানে একটি দ্রুত মিক্সিনস ডেমো ... প্রথমে, আপনি যে স্বাদগুলি মিশ্রিত করতে চান তা:

class CanEat {
    public eat() {
        alert('Munch Munch.');
    }
}

class CanSleep {
    sleep() {
        alert('Zzzzzzz.');
    }
}

তারপরে মিক্সিন তৈরির ম্যাজিক পদ্ধতি (আপনার প্রোগ্রামের কোথাও কোথাও একবারে আপনার এটি প্রয়োজন ...)

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
             if (name !== 'constructor') {
                derivedCtor.prototype[name] = baseCtor.prototype[name];
            }
        });
    }); 
}

এবং তারপরে আপনি মিশ্রণ স্বাদ থেকে একাধিক উত্তরাধিকার সহ ক্লাস তৈরি করতে পারেন:

class Being implements CanEat, CanSleep {
        eat: () => void;
        sleep: () => void;
}
applyMixins (Being, [CanEat, CanSleep]);

মনে রাখবেন যে এই শ্রেণিতে কোনও প্রকৃত বাস্তবায়ন নেই - এটি "ইন্টারফেস" এর প্রয়োজনীয়তাগুলি পাস করার জন্য যথেষ্ট। কিন্তু যখন আমরা এই শ্রেণিটি ব্যবহার করি - এটি সমস্ত কার্যকর।

var being = new Being();

// Zzzzzzz...
being.sleep();

4
এখানে টাইপ করা বিষয় হ্যান্ডবুক মধ্যে Mixins অধ্যায় (কিন্তু স্টিভ প্রায় কাছাকাছি সব আপনি এই উত্তর জানতে এবং তার সাথে যুক্ত প্রবন্ধে প্রয়োজন আবৃত) typescriptlang.org/Handbook#mixins
ট্রয় Gizzi

4
টাইপ করা বিষয় 2.2 এখন Mixins সমর্থন
Flavien Volken

4
@ ফ্লাভিয়েন ভলকেন আপনি কি জানেন যে মাইক্রোসফ্ট কেন তাদের পুরাতন মিক্সিন বিভাগগুলি তাদের হ্যান্ডবুক ডকুমেন্টেশনে রেখেছিল? যাইহোক, রিলিজ নোটগুলি আমার মতো টিএসে একটি শিক্ষানবিসের জন্য বুঝতে সত্যই কঠিন। টিএস 2.2+ মিক্সিস সহ টিউটোরিয়ালটির জন্য কোনও লিঙ্ক? ধন্যবাদ
ডেভিড ডি

4
এই উদাহরণটিতে দেখানো মিক্সিনগুলি করার "পুরানো উপায়" "নতুন উপায়" (টাইপস্ক্রিপ ২.২+) এর চেয়ে সহজ। আমি জানি না কেন তারা এটিকে এত কঠিন করে তুলেছিল।
টোক্কোভিল

4
কারণটি "পুরানো উপায়" সঠিকভাবে টাইপটি পেতে পারে না get
ইউনিয়ন

25

আমি এখানে বর্ণিত নতুন মিক্সিন পদ্ধতির ব্যবহারের পরামর্শ দেব: https://blogs.msdn.microsoft.com/typescript/2017/02/22/annoucing-typescript-2-2/

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

এই পদ্ধতির টিএস প্লেগ্রাউন্ড সাইটে পরীক্ষা করা হতে পারে ।

বাস্তবায়ন এখানে:

class MainClass {
    testMainClass() {
        alert("testMainClass");
    }
}

const addSecondInheritance = (BaseClass: { new(...args) }) => {
    return class extends BaseClass {
        testSecondInheritance() {
            alert("testSecondInheritance");
        }
    }
}

// Prepare the new class, which "inherits" 2 classes (MainClass and the cass declared in the addSecondInheritance method)
const SecondInheritanceClass = addSecondInheritance(MainClass);
// Create object from the new prepared class
const secondInheritanceObj = new SecondInheritanceClass();
secondInheritanceObj.testMainClass();
secondInheritanceObj.testSecondInheritance();

হয় SecondInheritanceClassউদ্দেশ্যমূলকভাবে সংজ্ঞায়িত করা অথবা আমি কিছু অনুপস্থিত করছি? টিএস খেলার মাঠে এই কোডটি লোড করার সময়, এটি বলে expecting =>। পরিশেষে, আপনি ঠিক কি ঘটতে যাচ্ছেন ঠিক যেমন ভেঙে ফেলতে পারেন addSecondInheritanceযেমন এর উদ্দেশ্য কী new (...args)?
Seanny123

এই জাতীয় মিশ্রণ বাস্তবায়নের মূল বিষয় যা উভয় শ্রেণীর সমস্ত পদ্ধতি এবং বৈশিষ্ট্য স্বতঃপূরণ আইডিই সাহায্যে প্রদর্শিত হবে। আপনি যদি চান তবে আপনি ২ য় শ্রেণির সংজ্ঞা দিতে পারেন এবং ফেন্টনের প্রস্তাবিত পদ্ধতির ব্যবহার করতে পারেন, তবে এই ক্ষেত্রে আইডিই স্বতঃপূরণ কাজ করবে না। {নতুন (... args)} - এই কোড একটি বস্তু যা বর্গ হওয়া উচিত বর্ণনা (আপনি হিজড়া ইন্টারফেসগুলি সম্পর্কে হ্যান্ডবুকে আরও পড়তে পারে: typescriptlang.org/docs/handbook/interfaces.html
মার্ক Dolbyrev

4
এখানে সমস্যাটি টিএসের এখনও পরিবর্তিত ক্লাস সম্পর্কে কোনও ধারণা নেই। আমি টাইপ করতে secondInheritanceObj.some()পারি এবং কোনও সতর্কতা বার্তা পাই না।
এসএফ

মিশ্র শ্রেণি ইন্টারফেস মান্য করে কিনা তা কীভাবে পরীক্ষা করবেন?
rilut

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

12

দুর্ভাগ্যক্রমে টাইপস্ক্রিপ্ট একাধিক উত্তরাধিকার সমর্থন করে না। সুতরাং কোনও সম্পূর্ণ তুচ্ছ উত্তর নেই, সম্ভবত আপনার প্রোগ্রামটি পুনর্গঠন করতে হবে

এখানে কয়েকটি পরামর্শ:

  • যদি এই অতিরিক্ত শ্রেণিতে এমন আচরণ থাকে যা আপনার অনেক উপশ্রেণী ভাগ করে নেয় তবে এটি শীর্ষ শ্রেণীর কোথাও শ্রেণি শ্রেণিবিন্যাসের মধ্যে toোকানো বুদ্ধিমান। হতে পারে আপনি এই শ্রেণীর থেকে স্প্রাইট, টেক্সচার, স্তর, ... এর সাধারণ সুপারক্লাস সংগ্রহ করতে পারেন? এটি হিরেরকি টাইপের কোনও ভাল জায়গা খুঁজে পেলে এটি একটি ভাল পছন্দ হবে। তবে আমি কেবল এলোমেলো পয়েন্টে এই শ্রেণিটি সন্নিবেশ করানোর পরামর্শ দেব না। উত্তরাধিকার একটি "সম্পর্ক একটি" প্রকাশ করে যেমন কুকুর একটি প্রাণী, একটি টেক্সচার এই শ্রেণীর উদাহরণ। আপনাকে নিজেরাই জিজ্ঞাসা করতে হবে, যদি এটি সত্যই আপনার কোডের বস্তুর মধ্যে সম্পর্কের মডেল হয়। একটি যৌক্তিক উত্তরাধিকার গাছ খুব মূল্যবান

  • যদি অতিরিক্ত শ্রেণি শ্রেণিবিন্যাসের মধ্যে যৌক্তিকভাবে মাপসই না হয় তবে আপনি সমষ্টিটি ব্যবহার করতে পারেন। এর অর্থ হ'ল আপনি এই শ্রেণীর প্রকারের একটি উদাহরণ ভেরিয়েবল স্প্রিট, টেক্সচার, স্তর, এর একটি সাধারণ সুপারক্লাসে যুক্ত করেন ... তারপরে আপনি সমস্ত উপক্লাসে তার গেটর / সেটারের সাহায্যে ভেরিয়েবলটি অ্যাক্সেস করতে পারেন। এই মডেলগুলির একটি "সম্পর্ক রয়েছে"।

  • আপনি নিজের শ্রেণিকে ইন্টারফেসে রূপান্তর করতে পারেন। তারপরে আপনি আপনার সমস্ত ক্লাসের সাথে ইন্টারফেসটি প্রসারিত করতে পারেন তবে প্রতিটি ক্লাসে পদ্ধতিগুলি সঠিকভাবে প্রয়োগ করতে হবে। এর অর্থ কিছু কোড রিডানডেনসি তবে এই ক্ষেত্রে বেশি নয়।

আপনাকে নিজেরাই সিদ্ধান্ত নিতে হবে যে কোন পদ্ধতিকে আপনি সবচেয়ে বেশি পছন্দ করেন। ব্যক্তিগতভাবে আমি ক্লাসটি একটি ইন্টারফেসে রূপান্তর করার পরামর্শ দেব।

একটি টিপ: টাইপসক্রিপ্ট বৈশিষ্ট্যগুলি সরবরাহ করে, যা গ্রাহকরা এবং সেটটারগুলির জন্য সিনট্যাকটিক চিনি। আপনি এটি একবার দেখে নিতে পারেন: http://blogs.microsoft.co.il/gilf/2013/01/22/creating-properties-in-typescript/


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

আকর্ষণীয় লিঙ্কটি আসলে, তবে আমি সমস্যাটি সমাধান করতে কোনও ব্যবহারের মামলা দেখতে পাচ্ছি না।
ভাদোরকোয়েস্ট

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

PIXIনিজেই কোনও শ্রেণি নয়, এটি একটি মডিউল, এটি বাড়ানো যাবে না, তবে আপনি ঠিক বলেছেন, এটি যদি একটি কার্যকর বিকল্প হত তবে তা হত!
ভাদোরাকোয়েস্ট

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

12

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

// The following line is only for intellisense to work
interface Shopperholic extends Buyer, Transportable {}

class Shopperholic {
  // The following line is where we "extend" from other 2 classes
  @use( Buyer, Transportable ) this 
  price = 2000;
}

8

আমি মনে করি যে আরও অনেক ভাল পদ্ধতির রয়েছে, যা শক্ত প্রকারের সুরক্ষা এবং স্কেলিবিলিটির জন্য অনুমতি দেয় ।

প্রথমে ইন্টারফেসগুলি ঘোষণা করুন যা আপনি আপনার টার্গেট শ্রেণিতে প্রয়োগ করতে চান:

interface IBar {
  doBarThings(): void;
}

interface IBazz {
  doBazzThings(): void;
}

class Foo implements IBar, IBazz {}

এখন আমাদের Fooক্লাসে প্রয়োগটি যুক্ত করতে হবে । আমরা ক্লাস মিক্সিনগুলি ব্যবহার করতে পারি যা এই ইন্টারফেসগুলি প্রয়োগ করে:

class Base {}

type Constructor<I = Base> = new (...args: any[]) => I;

function Bar<T extends Constructor>(constructor: T = Base as any) {
  return class extends constructor implements IBar {
    public doBarThings() {
      console.log("Do bar!");
    }
  };
}

function Bazz<T extends Constructor>(constructor: T = Base as any) {
  return class extends constructor implements IBazz {
    public doBazzThings() {
      console.log("Do bazz!");
    }
  };
}

Fooশ্রেণীর মিশ্রণের সাথে শ্রেণি প্রসারিত করুন :

class Foo extends Bar(Bazz()) implements IBar, IBazz {
  public doBarThings() {
    super.doBarThings();
    console.log("Override mixin");
  }
}

const foo = new Foo();
foo.doBazzThings(); // Do bazz!
foo.doBarThings(); // Do bar! // Override mixin

4
বার এবং বাজ ফাংশনগুলির ফিরে আসা প্রকারগুলি কী কী?
লুক স্কাইওয়াকার

3

একটি খুব হ্যাকি সমাধান হ'ল আপনি যে ক্লাসটি উত্তরাধিকার সূত্রে পেতে চান তার মধ্য দিয়ে নতুন প্যারেন্ট ক্লাসে একের পর এক ফাংশন যোগ করা থেকে উত্তীর্ণ হতে হবে

class ChildA {
    public static x = 5
}

class ChildB {
    public static y = 6
}

class Parent {}

for (const property in ChildA) {
    Parent[property] = ChildA[property]
}
for (const property in ChildB) {
    Parent[property] = ChildB[property]
}


Parent.x
// 5
Parent.y
// 6

সমস্ত বৈশিষ্ট্যাবলী ChildAএবং ChildBএখন থেকে অ্যাক্সেস করা যেতে পারে Parentবর্গ, কিন্তু তারা যার অর্থ আপনি যেমন সতর্কবার্তা পাবেন স্বীকৃত হতে হবেProperty 'x' does not exist on 'typeof Parent'



0

এখানে ইতিমধ্যে অনেক ভাল উত্তর আছে, তবে আমি কেবল একটি উদাহরণ দিয়ে দেখাতে চাই যে আপনি বর্ধিত শ্রেণিতে অতিরিক্ত কার্যকারিতা যুক্ত করতে পারেন;

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            if (name !== 'constructor') {
                derivedCtor.prototype[name] = baseCtor.prototype[name];
            }
        });
    });
}

class Class1 {
    doWork() {
        console.log('Working');
    }
}

class Class2 {
    sleep() {
        console.log('Sleeping');
    }
}

class FatClass implements Class1, Class2 {
    doWork: () => void = () => { };
    sleep: () => void = () => { };


    x: number = 23;
    private _z: number = 80;

    get z(): number {
        return this._z;
    }

    set z(newZ) {
        this._z = newZ;
    }

    saySomething(y: string) {
        console.log(`Just saying ${y}...`);
    }
}
applyMixins(FatClass, [Class1, Class2]);


let fatClass = new FatClass();

fatClass.doWork();
fatClass.saySomething("nothing");
console.log(fatClass.x);

0

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

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