বেশিরভাগ পরিপক্ক কোটলিন কোডে, আপনি নীচে এই নিদর্শনগুলির একটি খুঁজে পাবেন। প্রপার্টি ডেলিগেটস ব্যবহার করার পদ্ধতিটি কোটলিনের ক্ষুদ্রতম কোড তৈরির ক্ষমতার সুযোগ নেয়।
দ্রষ্টব্য: এখানে কোডটির জন্য java.util.Logging
তবে একই তত্ত্বটি কোনও লগিং লাইব্রেরিতে প্রয়োগ হয়
স্ট্যাটিক-মত (সাধারণ, প্রশ্নে আপনার জাভা কোডের সমতুল্য)
আপনি যদি লগিং সিস্টেমের মধ্যে সেই হ্যাশ লুকের পারফরম্যান্সে বিশ্বাস রাখতে না পারেন, তবে আপনার জাভা কোডের সাথে আপনি এমন কোনও সহকর্মী অবজেক্ট ব্যবহার করতে পারেন যা একটি ঘটনা ধরে রাখতে পারে এবং আপনার কাছে একটি স্ট্যাটিকের মতো বোধ করতে পারে।
class MyClass {
companion object {
val LOG = Logger.getLogger(MyClass::class.java.name)
}
fun foo() {
LOG.warning("Hello from MyClass")
}
}
আউটপুট তৈরি:
26 ডিসেম্বর, 2015 11:28:32 এএমএম ফু org.stackoverflow.kotlin.test.MyClass
ইনফো: মাই ক্লাস থেকে হ্যালো
এখানে সাহাবী অবজেক্টগুলির জন্য আরও: কম্বিয়ান অবজেক্টস ... এছাড়াও নোট করুন যে উপরের নমুনায় লগারের জন্য MyClass::class.java
টাইপের উদাহরণ পাওয়া যায় Class<MyClass>
, যেখানে this.javaClass
টাইপের উদাহরণ পাওয়া যায় Class<MyClass.Companion>
।
প্রতি শ্রেণীর ইনস্ট্যান্স (সাধারণ)
তবে, উদাহরণস্বরূপ স্তরে কল করা এবং লগার পাওয়া এড়ানোর কোনও কারণ নেই। আপনার উল্লিখিত অডিও জাভা পদ্ধতিটি পুরানো এবং পারফরম্যান্সের ভয়ের ভিত্তিতে, যেখানে ক্লাস প্রতি লগার ইতিমধ্যে গ্রহের প্রায় কোনও যুক্তিসঙ্গত লগিং সিস্টেম দ্বারা ক্যাশে হয়েছে। লগার অবজেক্টটি ধরে রাখতে কেবল সদস্য তৈরি করুন।
class MyClass {
val LOG = Logger.getLogger(this.javaClass.name)
fun foo() {
LOG.warning("Hello from MyClass")
}
}
আউটপুট তৈরি:
26 ডিসেম্বর, 2015 11:28:44 এএম org.stackoverflow.kotlin.test.MyClass foo তথ্য: মাইক্লাস থেকে হ্যালো
আপনি উদাহরণস্বরূপ এবং প্রতি শ্রেণীর পার্থক্য উভয়ই পারফরম্যান্স পরীক্ষা করতে পারেন এবং বেশিরভাগ অ্যাপ্লিকেশনের জন্য কোনও বাস্তবসম্মত পার্থক্য রয়েছে কিনা তা দেখতে পারেন।
সম্পত্তি প্রতিনিধি (সাধারণ, সবচেয়ে মার্জিত)
আরেকটি পদ্ধতির, যা @ জাইরের অন্য উত্তরে প্রস্তাবিত, একটি সম্পত্তি প্রতিনিধি তৈরি করা, যা আপনি চাইলে অন্য যে কোনও শ্রেণিতে যুক্তিযুক্তভাবে অবিচ্ছিন্নভাবে ব্যবহার করতে পারেন। এটি করার একটি সহজ উপায় আছে যেহেতু কোটলিন Lazy
ইতিমধ্যে একটি প্রতিনিধি সরবরাহ করে, আমরা কেবল এটি কোনও ফাংশনে গুটিয়ে রাখতে পারি । এখানে একটি কৌশলটি হ'ল যদি আমরা বর্তমানে প্রতিনিধি ব্যবহার করে ক্লাসের ধরণটি জানতে চাই তবে আমরা এটিকে যে কোনও ক্লাসে একটি এক্সটেনশন ফাংশন হিসাবে দেখি:
fun <R : Any> R.logger(): Lazy<Logger> {
return lazy { Logger.getLogger(unwrapCompanionClass(this.javaClass).name) }
}
// see code for unwrapCompanionClass() below in "Putting it all Together section"
এই কোডটি এটিও নিশ্চিত করে যে আপনি যদি এটি কোনও কম্পেনিয়ান অবজেক্টে ব্যবহার করেন তবে লগারের নাম একই হবে যেমন আপনি নিজেই এটি ক্লাসে ব্যবহার করেছেন। এখন আপনি কেবল:
class Something {
val LOG by logger()
fun foo() {
LOG.info("Hello from Something")
}
}
প্রতি শ্রেণীর উদাহরণের জন্য, বা আপনি যদি প্রতি ক্লাসে একটি উদাহরণ সহ আরও স্থিতিশীল হতে চান:
class SomethingElse {
companion object {
val LOG by logger()
}
fun foo() {
LOG.info("Hello from SomethingElse")
}
}
এবং foo()
এই উভয় ক্লাসে কল করা থেকে আপনার আউটপুটটি হ'ল :
26 ডিসেম্বর, 2015 11:30:55 পূর্বাহ্নে org.stackoverflow.kotlin.test. কিছু কথা ফুটিয়ে তুলেছে তথ্য: হ্যালো কিছু থেকে
26 ডিসেম্বর, 2015 11:30:55 এএম org.stackoverflow.kotlin.test.SomethingEll foo তথ্য: হ্যমথ সামথিংহেলস থেকে
এক্সটেনশন ফাংশন (কোনও নাম স্থানের "দূষণ" এর কারণে এক্ষেত্রে অস্বাভাবিক)
কোটলিনের কয়েকটি গোপন কৌশল রয়েছে যা আপনাকে এই কোডটির কিছুটিকে আরও ছোট করে তুলতে দেয়। আপনি ক্লাসে এক্সটেনশন ফাংশন তৈরি করতে পারেন এবং তাই তাদের অতিরিক্ত কার্যকারিতা দিতে পারেন। উপরের মন্তব্যে একটি পরামর্শ ছিল Any
লগার ফাংশন সহ প্রসারিত করা । এটি যে কোনও সময় কোনও ক্লাসে তাদের আইডিইতে কোড-সমাপ্তি ব্যবহার করার সাথে সাথে শব্দটি তৈরি করতে পারে। তবে সম্প্রসারণ Any
বা অন্য কোনও মার্কার ইন্টারফেসের একটি গোপন সুবিধা রয়েছে : আপনি বোঝাতে পারেন যে আপনি নিজের শ্রেণিটি প্রসারিত করছেন এবং তাই আপনার মধ্যে যে শ্রেণিটি রয়েছে তা সনাক্ত করুন। তাই না? কম বিভ্রান্ত হওয়ার জন্য, এখানে কোডটি দেওয়া হয়েছে:
// extend any class with the ability to get a logger
fun <T: Any> T.logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
এখন একটি শ্রেণীর মধ্যে (বা সহকর্মী অবজেক্ট), আমি কেবল নিজের ক্লাসে এই এক্সটেনশনটিকে কল করতে পারি:
class SomethingDifferent {
val LOG = logger()
fun foo() {
LOG.info("Hello from SomethingDifferent")
}
}
উত্পাদন আউটপুট:
26 ডিসেম্বর, 2015 11:29:12 এএম org.stackoverflow.kotlin.test.SomeomingDifferent foo তথ্য: হ্যালো সামথিংডিফারেন্স থেকে
মূলত, কোডটি এক্সটেনশনের কল হিসাবে দেখা হয় Something.logger()
। সমস্যাটি হ'ল নিম্নলিখিত শ্রেণিগুলিতে অন্যান্য শ্রেণিতে "দূষণ" তৈরি করা সত্য হতে পারে:
val LOG1 = "".logger()
val LOG2 = Date().logger()
val LOG3 = 123.logger()
মার্কার ইন্টারফেসে এক্সটেনশন ফাংশন (কীভাবে সাধারণ, "বৈশিষ্ট্যগুলি" তবে সাধারণ মডেল তা নিশ্চিত নয়)
এক্সটেনশানগুলির ব্যবহার পরিষ্কার এবং "দূষণ" হ্রাস করতে, আপনি প্রসারিত করতে একটি মার্কার ইন্টারফেস ব্যবহার করতে পারেন:
interface Loggable {}
fun Loggable.logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
অথবা এমনকি ডিফল্ট প্রয়োগের মাধ্যমে পদ্ধতিটিকে ইন্টারফেসের অংশ হিসাবে তৈরি করুন:
interface Loggable {
public fun logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
}
এবং আপনার শ্রেণিতে এই বৈচিত্রগুলির যে কোনও একটি ব্যবহার করুন:
class MarkedClass: Loggable {
val LOG = logger()
}
উত্পাদন আউটপুট:
26 ডিসেম্বর, 2015 11:41:01 এএম org.stackoverflow.kotlin.test.MarkedClass foo তথ্য: মার্কডক্লাস থেকে হ্যালো
আপনি যদি লগার ধরে রাখার জন্য অভিন্ন ক্ষেত্র তৈরি করতে বাধ্য করতে চান, তবে এই ইন্টারফেসটি ব্যবহার করার সময় আপনাকে সহজেই প্রয়োগকারীকে একটি ক্ষেত্রের প্রয়োজন হতে পারে যেমন LOG
:
interface Loggable {
val LOG: Logger // abstract required field
public fun logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
}
এখন ইন্টারফেসের প্রয়োগকারীকে অবশ্যই এর মতো দেখতে হবে:
class MarkedClass: Loggable {
override val LOG: Logger = logger()
}
অবশ্যই, একটি বিমূর্ত বেস শ্রেণি একই কাজ করতে পারে, ইন্টারফেস উভয় বিকল্প থাকা এবং একটি ইন্টারফেস ক্লাস যে ইন্টারফেস প্রয়োগ করে নমনীয়তা এবং অভিন্নতা দেয়:
abstract class WithLogging: Loggable {
override val LOG: Logger = logger()
}
// using the logging from the base class
class MyClass1: WithLogging() {
// ... already has logging!
}
// providing own logging compatible with marker interface
class MyClass2: ImportantBaseClass(), Loggable {
// ... has logging that we can understand, but doesn't change my hierarchy
override val LOG: Logger = logger()
}
// providing logging from the base class via a companion object so our class hierarchy is not affected
class MyClass3: ImportantBaseClass() {
companion object : WithLogging() {
// we have the LOG property now!
}
}
এটি একসাথে রাখা (একটি ছোট সহায়ক লাইব্রেরি)
উপরের যে কোন বিকল্পটি ব্যবহার করা সহজ করার জন্য এখানে একটি ছোট সহায়ক লাইব্রেরি রয়েছে। কোটলিনে এটিকে আপনার পছন্দমতো করে তুলতে এপিআই প্রসারিত করা সাধারণ। হয় এক্সটেনশন বা শীর্ষ স্তরের ফাংশনগুলিতে। লগার কিভাবে তৈরি করবেন তার বিকল্পগুলির জন্য এখানে একটি মিশ্রণ এবং সমস্ত বৈচিত্র দেখানো একটি নমুনা:
// Return logger for Java class, if companion object fix the name
fun <T: Any> logger(forClass: Class<T>): Logger {
return Logger.getLogger(unwrapCompanionClass(forClass).name)
}
// unwrap companion class to enclosing class given a Java Class
fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> {
return ofClass.enclosingClass?.takeIf {
ofClass.enclosingClass.kotlin.companionObject?.java == ofClass
} ?: ofClass
}
// unwrap companion class to enclosing class given a Kotlin Class
fun <T: Any> unwrapCompanionClass(ofClass: KClass<T>): KClass<*> {
return unwrapCompanionClass(ofClass.java).kotlin
}
// Return logger for Kotlin class
fun <T: Any> logger(forClass: KClass<T>): Logger {
return logger(forClass.java)
}
// return logger from extended class (or the enclosing class)
fun <T: Any> T.logger(): Logger {
return logger(this.javaClass)
}
// return a lazy logger property delegate for enclosing class
fun <R : Any> R.lazyLogger(): Lazy<Logger> {
return lazy { logger(this.javaClass) }
}
// return a logger property delegate for enclosing class
fun <R : Any> R.injectLogger(): Lazy<Logger> {
return lazyOf(logger(this.javaClass))
}
// marker interface and related extension (remove extension for Any.logger() in favour of this)
interface Loggable {}
fun Loggable.logger(): Logger = logger(this.javaClass)
// abstract base class to provide logging, intended for companion objects more than classes but works for either
abstract class WithLogging: Loggable {
val LOG = logger()
}
আপনি যে কোনওটিকে রাখতে চান তা চয়ন করুন এবং এখানে সমস্ত বিকল্পের ব্যবহার রয়েছে:
class MixedBagOfTricks {
companion object {
val LOG1 by lazyLogger() // lazy delegate, 1 instance per class
val LOG2 by injectLogger() // immediate, 1 instance per class
val LOG3 = logger() // immediate, 1 instance per class
val LOG4 = logger(this.javaClass) // immediate, 1 instance per class
}
val LOG5 by lazyLogger() // lazy delegate, 1 per instance of class
val LOG6 by injectLogger() // immediate, 1 per instance of class
val LOG7 = logger() // immediate, 1 per instance of class
val LOG8 = logger(this.javaClass) // immediate, 1 instance per class
}
val LOG9 = logger(MixedBagOfTricks::class) // top level variable in package
// or alternative for marker interface in class
class MixedBagOfTricks : Loggable {
val LOG10 = logger()
}
// or alternative for marker interface in companion object of class
class MixedBagOfTricks {
companion object : Loggable {
val LOG11 = logger()
}
}
// or alternative for abstract base class for companion object of class
class MixedBagOfTricks {
companion object: WithLogging() {} // instance 12
fun foo() {
LOG.info("Hello from MixedBagOfTricks")
}
}
// or alternative for abstract base class for our actual class
class MixedBagOfTricks : WithLogging() { // instance 13
fun foo() {
LOG.info("Hello from MixedBagOfTricks")
}
}
এই নমুনায় তৈরি লগারের সমস্ত 13 টি উদাহরণ একই লগারের নাম এবং আউটপুট উত্পাদন করবে:
26 ডিসেম্বর, ২০১৫ 11:39:00 এএম org.stackoverflow.kotlin.test. মিক্সডব্যাগঅফট্রিক্স ফাঁস ইনফো: মিক্সডব্যাগঅফট্রিক্স থেকে হ্যালো
দ্রষ্টব্য: দ্যunwrapCompanionClass()
পদ্ধতি নিশ্চিত করে যে আমরা সহচর বস্তুর বরং এনক্লোজিং ক্লাস নামাঙ্কিত এটির উৎপন্ন হবে না। সহকর্মী অবজেক্টটি সহ ক্লাসটি সন্ধান করার এটি বর্তমান প্রস্তাবিত উপায়। নামটি ব্যবহার করে " $ কম্পায়েনিয়ান" কেটে ফেলা removeSuffix()
কাজ করে না, কারণ সহযোদ্ধা অবজেক্টগুলিকে কাস্টম নাম দেওয়া যেতে পারে।