java - যখনই জাভাতে প্রযোজ্য "চূড়ান্ত" সংশোধনকারী ব্যবহার করা




oop (17)

আপনি এটি ব্যবহার করার আগে চূড়ান্ত কীওয়ার্ড সম্পূর্ণ ব্যবহার বুঝতে হবে। এটি প্রয়োগ এবং ভেরিয়েবল, ক্ষেত্র, পদ্ধতি এবং ক্লাসে ভিন্ন হতে পারে

আমি আরো বিস্তারিত জানার জন্য নিচের নিবন্ধটি চেক আউট সুপারিশ চাই।

চূড়ান্ত শব্দ ফাইনাল শব্দ

জাভাতে, প্রতিটি পরিবর্তনশীল (স্থানীয় বা বর্গ), প্যারামিটার ফাইনাল ঘোষণা করার অভ্যাস আছে যদি তারা সত্যিই হয়।

যদিও এটি কোডটিকে আরও বেশি শব্দের সংকেত দেয় তবে এটি কোডটি সহজে পড়ার / আটকে রাখতে এবং ইচ্ছাকে স্পষ্টভাবে চিহ্নিত করার কারণে ভুলগুলি প্রতিরোধ করতে সহায়তা করে।

এই আপনার চিন্তা কি এবং আপনি কি অনুসরণ করেন?


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


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

এটি করার জন্য যদি কোনও সত্যিকারের কারণ না থাকে (যতক্ষন না আপনি সেই পরিবর্তনশীল সম্পর্কে চূড়ান্ত কোনও নির্দিষ্ট বিন্দু তৈরি করতে চান) আমি এটি কোডটি কম পাঠযোগ্য বলে মনে করি না বলে আমি এটি করতে চাই না।

তবে, যদি আপনি এটি কোডটি পড়তে কঠিন না হয়ে লিখতে বেশি সময় না পান তবে সব উপায়ে যান।

সম্পাদনা: একটি স্পষ্টকরণ হিসাবে (এবং ডাউন ডাউন ভোটগুলি জয় করার প্রচেষ্টা), আমি বলছি না যে সংশ্লেষগুলিকে চূড়ান্ত রূপে চিহ্নিত করবেন না, আমি বলছি যে এরকম কিছু করবেন না:

public String doSomething() {
  final String first = someReallyComplicatedExpressionToGetTheString();
  final String second = anotherReallyComplicatedExpressionToGetAnother();

  return first+second;
}

এটা শুধু পড়তে কঠিন (আমার মতে) কোড করে তোলে।

এটি মনে রাখাও গুরুত্বপূর্ণ যে সমস্ত চূড়ান্ত কাজ আপনাকে একটি পরিবর্তনশীল পুনঃনির্মাণ থেকে আটকাতে পারে, এটি এটি অপ্রয়োজনীয় বা এরকম কিছু করে না।


আমি পদ্ধতিতে বা শ্রেণীগুলিতে চূড়ান্তভাবে চূড়ান্ত ব্যবহার করি কারণ আমি লোকেদের তাদের ওভাররাইড করার অনুমতি দিতে চাই।

অন্যথা, আমি কেবলমাত্র এটি public/private static final type SOME_CONSTANT;


আমি বস্তুর গুণাবলী জন্য সব সময় final ব্যবহার।

অবজেক্ট বৈশিষ্ট্য ব্যবহার করা হয় যখন final শব্দ দৃশ্যমানতা semantics আছে। মূলত, একটি চূড়ান্ত বস্তুর গুণমানের মান নির্ধারণ করা হয়-কন্সট্রকটরটি ফেরত দেওয়ার আগে। এর মানে হল যে যতক্ষণ আপনি this রেফারেন্সটিকে কনস্ট্রাকটর থেকে অব্যাহতি দেবেন না এবং আপনি আপনার সমস্ত গুণাবলীগুলির জন্য final ব্যবহার করবেন, ততক্ষণ আপনার অবজেক্ট (জাভা 5 সেমেটিক্সের অধীনে) সঠিকভাবে তৈরি করা হবে এবং এটি অপরিবর্তনীয়ও হতে পারে নিরাপদে অন্যান্য থ্রেড প্রকাশিত।

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

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

আমি আমার ক্লাস চূড়ান্ত সংখ্যাগরিষ্ঠ করা উচিত অনুমান, কিন্তু আমি এখনও এখনো খরগোশ মধ্যে অর্জিত না।


আমি ভিতর এবং বাইরে পদ্ধতির জন্য এটি ব্যবহার।

আমি কেবল কখনও কখনও পদ্ধতির জন্য এটি ব্যবহার করি কারণ আমি জানি না যে একটি উপশ্রেণী কোনও প্রদত্ত পদ্ধতি (কোনও কারণের জন্য) ওভাররাইড করতে চাই না।

ক্লাস হিসাবে, শুধুমাত্র কিছু অবকাঠামো ক্লাসের জন্য, আমি চূড়ান্ত ক্লাস ব্যবহার করেছি।

একটি ফাংশন পরামিতি একটি ফাংশন ভিতরে লেখা হয় যদি IntelliJ IDEA আপনাকে সতর্ক করে। সুতরাং, আমি ফাংশন আর্গুমেন্টের জন্য চূড়ান্ত ব্যবহার বন্ধ করেছি। আমি জাভা রানটাইম লাইব্রেরির পাশাপাশি তাদের দেখতে পাই না।


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

বেশিরভাগ একই সদস্য ভেরিয়েবলগুলিতেও প্রযোজ্য, কারণ তারা ধ্রুবকের ক্ষেত্রে ব্যতীত সামান্য সুবিধা দেয়।

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

কিন্তু আরে, এটা শুধু আমার মতামত :-)


আরেকটি সতর্কতা হল যে অনেকেই চূড়ান্তভাবে অর্থহীন বলে মনে করেন যে ইনস্ট্যান্সের পরিবর্তনশীল বিষয়গুলি পরিবর্তিত হতে পারে না বরং রেফারেন্স পরিবর্তন করতে পারে।


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

তবে, যদি আপনি নিজের কোডে অনেকগুলি চূড়ান্ত বিবৃতি দেওয়ার প্রয়োজন বোধ করেন। যে আপনি একটি ভাল ইঙ্গিত হতে পারে কিছু ভুল করছেন।

উপরের পোস্ট নিবন্ধটি এই উদাহরণ দেয়:

public void doSomething(int i, int j) {
    final int n = i + j; // must be declared final

    Comparator comp = new Comparator() {
        public int compare(Object left, Object right) {
            return n; // return copy of a local variable
        }
    };
}

উপর নজর রাখুন:

  • চূড়ান্ত ক্ষেত্রগুলি - ক্ষেত্রগুলিকে চিহ্নিত করে চূড়ান্ত শক্তিকে নির্মাণের শেষে সেট করা হবে, যা ক্ষেত্রের উল্লেখকে অপ্রয়োজনীয় করে তুলবে। এটি ক্ষেত্রগুলির নিরাপদ প্রকাশের অনুমতি দেয় এবং পরবর্তী পঠনগুলিতে সিঙ্ক্রোনাইজেশনের প্রয়োজনীয়তা এড়াতে পারে। (লক্ষ্য করুন যে কোন বস্তুর রেফারেন্সের জন্য, শুধুমাত্র ক্ষেত্রের রেফারেন্সটি অপরিবর্তনীয় - এমন বিষয় যা রেফারেন্স অবজেক্ট বোঝায় তা এখনও পরিবর্তন করতে পারে এবং এটি অপ্রয়োজনীয়তাকে প্রভাবিত করে।)
  • চূড়ান্ত স্ট্যাটিক ক্ষেত্র - যদিও আমি স্ট্যাটিক চূড়ান্ত ক্ষেত্রগুলি ব্যবহার করতে বেশ কয়েকটি ক্ষেত্রে এখন enums ব্যবহার করি।

বিবেচনা করুন কিন্তু বিচার্যভাবে ব্যবহার করুন:

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

মলদ্বার অনুভব না করা পর্যন্ত উপেক্ষা করুন:

  • পদ্ধতি প্যারামিটার এবং স্থানীয় ভেরিয়েবলগুলি - আমি মূলত এইটি করি কারণ আমি অলস এবং আমি এটি কোডটি আটকে রাখি। আমি পুরোপুরি স্বীকার করব যে চিহ্নিত পরামিতি এবং স্থানীয় পরিবর্তনগুলি যা আমি পরিবর্তন করতে যাচ্ছি তা হল "রাইটার"। আমি এটা ডিফল্ট ছিল ইচ্ছুক। কিন্তু এটি না এবং আমি সমস্ত ফাইনাল সঙ্গে কোড বুঝতে আরো কঠিন। যদি আমি অন্য কারো কোডে থাকি, তবে আমি তাদের খুঁজে বের করতে যাচ্ছি না কিন্তু যদি আমি নতুন কোড লিখি তবে আমি তাদের মধ্যে ঢুকতে দেব না। এক ব্যতিক্রম যেখানে আপনাকে কিছু চূড়ান্তভাবে চিহ্নিত করতে হবে যাতে আপনি অ্যাক্সেস করতে পারেন এটি একটি বেনামী ভিতরের ক্লাসের মধ্যে থেকে।

কার্যকরী জাভা একটি আইটেম যা বলে "অপ্রয়োজনীয় বস্তুর পক্ষে"। ক্ষেত্রগুলিকে চূড়ান্ত হিসাবে ঘোষণা করা আপনাকে এই দিকে কিছু ছোট পদক্ষেপ নিতে সহায়তা করে, তবে অবশ্যই এটির চেয়ে অপরিবর্তনীয় বস্তুগুলির আরো অনেক কিছু আছে।

যদি আপনি জানেন যে অবজেক্টগুলি অপ্রয়োজনীয় হয় তবে সেগুলিকে সিঙ্ক্রোনাইজেশনের উদ্বেগ ছাড়াই অনেকগুলি থ্রেড / ক্লায়েন্টের মধ্যে পড়ার জন্য ভাগ করা যেতে পারে এবং প্রোগ্রামটি কীভাবে চলবে তা নিয়ে যুক্তি করা সহজ।


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

class A {
    void foo() {
        //do something
    }
}
final class B extends A {
    void foo() {
    }
}
class Test {
    public void t(A v1, B v2) {
        v1.foo();
        v2.foo();
    }
}

চূড়ান্ত সবসময় ধ্রুবক জন্য ব্যবহার করা উচিত। ভেরিয়েবল সংজ্ঞায়িত করার নিয়মগুলি জটিল হলে এটি স্বল্পকালীন ভেরিয়েবলগুলির জন্য (এমনকি একটি পদ্ধতিতে) কার্যকর।

উদাহরণ স্বরূপ:

final int foo;
if (a)
    foo = 1;
else if (b)
    foo = 2;
else if (c)
    foo = 3;
if (d)        // Compile error:  forgot the 'else'
    foo = 4;
else
    foo = -1;

জাভাতে ভেরিয়েবলগুলির সাথে ব্যবহৃত চূড়ান্ত যখন সি ++ তে ধ্রুবক জন্য একটি বিকল্প সরবরাহ করে। সুতরাং যখন চূড়ান্ত এবং স্ট্যাটিক একটি পরিবর্তনশীল জন্য ব্যবহার করা হয় এটি অনাক্রম্য হয়ে। একই সময়ে মাইগ্রেটেড সি ++ প্রোগ্রামারদের বেশ খুশি করে তোলে ;-)

রেফারেন্স ভেরিয়েবলগুলির সাথে ব্যবহৃত হলে এটি বস্তুর পুনঃ-রেফারেন্স করার অনুমতি দেয় না, যদিও বস্তুটি ম্যানিপুলেট করা যেতে পারে।

যখন একটি পদ্ধতির সাথে চূড়ান্তভাবে ব্যবহার করা হয়, তখন এটি উপ-ঘ্লাসগুলি দ্বারা পদ্ধতিটিকে অতিরিক্ত-বর্জিত করার অনুমতি দেয় না।

একবার ব্যবহারের খুব পরিষ্কার হলে যত্নের সাথে এটি ব্যবহার করা উচিত। পদ্ধতির উপর চূড়ান্ত ব্যবহার হিসাবে এটি প্রধানত নকশা উপর নির্ভর করে polymorphism সাহায্য করবে না।

ভেরিয়েবলগুলির জন্য শুধুমাত্র এটি ব্যবহার করা উচিত যখন আপনি নিশ্চিত হন যে পরিবর্তনশীলের মান কখনও পরিবর্তন হবে না। এছাড়াও নিশ্চিত করুন যে আপনি SUN দ্বারা উত্সর্গকৃত কোডিং কনভেনশন অনুসরণ করেন। উদাহরণস্বরূপ: চূড়ান্ত int COL_RE_RED = 1; (আন্ডারস্কোর দ্বারা পৃথক উচ্চতর ক্ষেত্রে)

একটি রেফারেন্স ভেরিয়েবলের সাথে, এটি শুধুমাত্র তখন ব্যবহার করুন যখন আমাদের একটি নির্দিষ্ট বস্তুর একটি অননুমোদিত রেফারেন্স প্রয়োজন।

পাঠযোগ্যতা অংশ সম্পর্কে, চূড়ান্ত সংশোধনকারী ব্যবহার করার সময় মন্তব্যগুলি একটি অত্যন্ত গুরুত্বপূর্ণ ভূমিকা পালন করে।


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

final FileInputStream in;
if(test)
  in = new FileInputStream("foo.txt");
else
  System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned

একটি পরিবর্তনশীল একবার একাধিক বরাদ্দ করা থেকে প্রতিরোধ করে, আপনি overbroad scoping নিরুৎসাহিত। এটার পরিবর্তে:

 String msg = null;
 for(int i = 0; i < 10; i++) {
     msg = "We are at position " + i;
     System.out.println(msg);
 }
 msg = null;

আপনি এই ব্যবহার করার জন্য উত্সাহিত করা হয়:

 for(int i = 0; i < 10; i++) {
     final String msg = "We are at position " + i;
     System.out.println(msg);
 }

কিছু লিঙ্ক:


চূড়ান্তভাবে অবশ্যই ধ্রুবক ব্যবহার করা উচিত, এবং immutability প্রয়োগ করা, কিন্তু পদ্ধতিতে অন্য গুরুত্বপূর্ণ ব্যবহার আছে।

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

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


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

সমস্ত কিছুকে final সংযোজন করা উচিত নয় যা আপনি পরিবর্তন করতে চান না (অথবা আপনার প্রোগ্রামে কাজকারী পরবর্তী প্রোগ্রামার) কেবল আপনার কোডের ফলে চিন্তার চিন্তার ভুল ব্যাখ্যা বা অপব্যবহার করবে। তারা এখন আপনার পূর্বে অপ্রয়োজনীয় জিনিস পরিবর্তন করতে চান যখন অন্তত এটা কিছু ঘন্টাধ্বনি রিং করা উচিত।

প্রথমত, আপনার কোডে অনেকগুলি final কীওয়ার্ড দেখতে এটি অদ্ভুত লাগছে, কিন্তু খুব শীঘ্রই আপনি নিজের শব্দটি দেখতে বন্ধ করুন এবং সহজেই মনে রাখবেন যে , জিনিসটি কখনই পরিবর্তন হবে না অন (আপনি আমার কাছ থেকে এটা নিতে পারেন ;-)

আমি এটা ভাল অনুশীলন মনে হয়। আমি সর্বদা এটি ব্যবহার করছি না, কিন্তু যখন আমি করতে পারি এবং এটি কিছু final লেবেল final আমি এটি করব।







oop