JavaRush /وبلاگ جاوا /Random-FA /سازندگان در جاوا

سازندگان در جاوا

در گروه منتشر شد
سلام! امروز به یک موضوع بسیار مهم که مربوط به اشیاء ما است نگاه خواهیم کرد. در اینجا بدون اغراق می توان گفت که شما هر روز از این دانش در کارهای واقعی استفاده خواهید کرد! ما در مورد سازنده ها صحبت خواهیم کرد. شاید برای اولین بار است که این اصطلاح را می شنوید، اما در واقع احتمالاً از سازنده ها استفاده کرده اید، اما خودتان متوجه آن نشده اید :) بعداً این را خواهیم دید.

سازنده در جاوا چیست و چرا به آن نیاز است؟

بیایید به دو مثال نگاه کنیم.
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car bugatti = new Car();
       bugatti.model = "Bugatti Veyron";
       bugatti.maxSpeed = 407;

   }
}
ما ماشین خود را ساختیم و مدل و حداکثر سرعت آن را تنظیم کردیم. با این حال، در یک پروژه واقعی، شی Car به وضوح بیش از 2 فیلد خواهد داشت. و مثلا 16 فیلد!
public class Car {

   String model;//model
   int maxSpeed;//max speed
   int wheels;// disk width
   double engineVolume;//engine capacity
   String color;//color
   int yearOfIssue;//year of issue
   String ownerFirstName;//Owner's name
   String ownerLastName;//owner's last name
   long price;//price
   boolean isNew;//new or not
   int placesInTheSalon;//number of seats in the cabin
   String salonMaterial;// interior material
   boolean insurance;//is it insured
   String manufacturerCountry;//manufacturer country
   int trunkVolume;// trunk volume
   int accelerationTo100km;//acceleration to 100 km/h in seconds


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

   }

}
ما یک شی جدید Car ایجاد کرده ایم . یک مشکل: ما 16 فیلد داریم، اما فقط 12 را مقداردهی اولیه کردیم ! اکنون از کد استفاده کنید تا آنهایی را که فراموش کرده ایم پیدا کنید! چندان آسان نیست، درست است؟ در چنین شرایطی، برنامه نویس به راحتی می تواند اشتباه کند و از مقداردهی اولیه یک فیلد صرف نظر کند. در نتیجه، رفتار برنامه اشتباه خواهد شد:
public class Car {

   String model;//model
   int maxSpeed;//max speed
   int wheels;// disk width
   double engineVolume;//engine capacity
   String color;//color
   int yearOfIssue;//year of issue
   String ownerFirstName;//Owner's name
   String ownerLastName;//owner's last name
   long price;//price
   boolean isNew;//new or not
   int placesInTheSalon;//number of seats in the cabin
   String salonMaterial;// interior material
   boolean insurance;//is it insured
   String manufacturerCountry;//manufacturer country
   int trunkVolume;// trunk volume
   int accelerationTo100km;//acceleration to 100 km/h in seconds


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model Bugatti Veyron. Engine size - " + bugatti.engineVolume + ", trunk - " + bugatti.trunkVolume + ", salon is made of" + bugatti.salonMaterial +
       ", disc width - " + bugatti.wheels + ". Was acquired in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
خروجی کنسول:
مدل بوگاتی ویرون. حجم موتور - 6.3 صندوق عقب - 0، داخل نول، عرض رینگ - 0. خریداری شده در سال 2018 توسط آقای null
خریدار شما که 2 میلیون دلار برای یک ماشین پرداخت کرده است، بدیهی است که دوست ندارد او را "آقای نول" خطاب کنند! اما به طور جدی، در نهایت، برنامه ما به یک شیء ساخته شده نادرست ختم شد - ماشینی با عرض رینگ 0 (یعنی بدون رینگ)، صندوق عقب گم شده، فضای داخلی ساخته شده از مواد ناشناخته، و حتی متعلق به شخص ناشناس . فقط می توان تصور کرد که چگونه چنین خطایی ممکن است در حین اجرای برنامه رخ دهد! ما باید به نحوی از چنین موقعیت هایی اجتناب کنیم. ما نیاز داریم که برنامه ما یک محدودیت داشته باشد: برای مثال هنگام ایجاد یک شیء وسیله نقلیه جدید، مدل و حداکثر سرعت باید همیشه برای آن مشخص شود. در غیر این صورت، اجازه ایجاد شی را ندهید. توابع سازنده به راحتی با این کار کنار می آیند. آنها نام خود را به دلیلی دریافت کردند. سازنده نوعی "اسکلت" کلاس را ایجاد می کند که هر شی جدید کلاس باید با آن مطابقت داشته باشد. برای راحتی، اجازه دهید به یک نسخه ساده تر از کلاس خودرو با دو فیلد بازگردیم. با توجه به نیازهای ما، سازنده کلاس خودرو به شکل زیر خواهد بود:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
و ایجاد یک شی اکنون به شکل زیر است:
public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 407);
}
توجه کنیدسازنده چگونه ایجاد می شود شبیه به یک متد معمولی است، اما نوع بازگشتی ندارد. در این حالت، نام کلاس در سازنده و همچنین با حرف بزرگ نشان داده می شود. در مورد ما - ماشین . علاوه بر این، سازنده از کلمه کلیدی new-to-y this استفاده می کند . "this" در انگلیسی به معنای "این، این" است. این کلمه به یک شی خاص اشاره دارد. کد در سازنده:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
تقریباً به معنای واقعی کلمه می توان ترجمه کرد: " مدل برای این ماشین (که اکنون در حال ایجاد آن هستیم) = آرگومان مدل که در سازنده مشخص شده است. maxSpeed ​​برای این ماشین (که در حال ایجاد آن هستیم) = آرگومان maxSpeed ​​که در سازنده مشخص شده است." این چیزی است که اتفاق افتاد:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car("Bugatti Veyron", 407);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
خروجی کنسول:
بوگاتی ویرون 407
سازنده با موفقیت مقادیر مورد نیاز را اختصاص داد. شاید متوجه شده باشید که یک سازنده بسیار شبیه به یک متد معمولی است! اینطور است: سازنده یک متد است، فقط کمی خاص :) درست مانند یک متد، ما پارامترهایی را به سازنده خود منتقل کردیم. و درست مانند فراخوانی یک متد، فراخوانی سازنده کار نخواهد کرد اگر آنها را مشخص نکنید:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car(); //error!
   }

}
ببینید، طراح آنچه را که ما در تلاش بودیم انجام دهیم، انجام داد. حالا شما نمی توانید یک ماشین بدون سرعت یا بدون مدل بسازید! شباهت بین سازنده ها و متدها به همین جا ختم نمی شود. درست مانند متدها، سازنده ها می توانند بیش از حد بارگذاری شوند. تصور کنید که 2 گربه در خانه دارید. شما یکی از آنها را به عنوان یک بچه گربه گرفتید و دومی را در بزرگسالی از خیابان به خانه آوردید و دقیقاً نمی دانید چند سال دارد. این بدان معنی است که برنامه ما باید بتواند گربه های دو نوع ایجاد کند - با نام و سن برای گربه اول، و فقط با یک نام - برای گربه دوم. برای انجام این کار، سازنده را بارگذاری می کنیم:
public class Cat {

   String name;
   int age;

   //for the first cat
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //for the second cat
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
به سازنده اصلی با پارامترهای "name" و "age"، یکی دیگر را فقط با نام اضافه کردیم. ما روش ها را به همین روش در درس های قبل اضافه بار کردیم. حالا ما می توانیم هر دو نسخه گربه را با موفقیت ایجاد کنیم :) چرا سازندگان مورد نیاز هستند؟  - 2آیا به خاطر دارید در ابتدای سخنرانی گفتیم که قبلاً از سازنده استفاده کرده اید، اما متوجه آن نشده اید؟ درست است. واقعیت این است که هر کلاس در جاوا یک سازنده به اصطلاح پیش فرض دارد. هیچ آرگومان ندارد، اما هر بار که هر شیء از هر کلاس ایجاد می شود، فعال می شود.
public class Cat {

   public static void main(String[] args) {

       Cat barsik = new Cat(); //this is where the default constructor worked
   }
}
در نگاه اول این قابل توجه نیست. خوب، ما یک شی ایجاد کردیم و آن را ایجاد کردیم، کار طراح کجاست؟ برای مشاهده این موضوع، اجازه دهید یک سازنده خالی برای کلاس Cat با دستان خود بنویسیم و در داخل آن عبارتی را در کنسول چاپ کنیم. اگر نمایش داده شود، سازنده کار کرده است.
public class Cat {

   public Cat() {
       System.out.println("Created a cat!");
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //this is where the default constructor worked
   }
}
خروجی کنسول:
آنها یک گربه خلق کردند!
اینم تاییدیه! سازنده پیش فرض همیشه به صورت نامرئی در کلاس های شما وجود دارد. اما باید یک ویژگی دیگر آن را بدانید. هنگامی که سازنده ای با آرگومان ایجاد می کنید، سازنده پیش فرض از کلاس ناپدید می شود. اثبات این، در واقع، ما قبلا در بالا دیده ایم. در اینجا در این کد:
public class Cat {

   String name;
   int age;

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //error!
   }
}
ما نمی‌توانستیم گربه‌ای بدون نام و سن بسازیم زیرا یک سازنده برای Cat : string + number تعریف کردیم. سازنده پیش فرض بلافاصله پس از این از کلاس ناپدید شد. بنابراین، حتما به خاطر داشته باشید: اگر به چندین سازنده در کلاس خود نیاز دارید، از جمله یک سازنده خالی، باید آن را جداگانه ایجاد کنید. به عنوان مثال، ما در حال ایجاد یک برنامه برای یک کلینیک دامپزشکی هستیم. کلینیک ما می خواهد کارهای خیر انجام دهد و به گربه های بی خانمانی که نه نام و نه سن آنها را نمی دانیم کمک کند. سپس کد ما باید به شکل زیر باشد:
public class Cat {

   String name;
   int age;

   //for domestic cats
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //for street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCat = new Cat();
   }
}
اکنون که به صراحت یک سازنده پیش‌فرض نوشته‌ایم، می‌توانیم از هر دو نوع cat ایجاد کنیم :) برای یک سازنده (مانند هر روش دیگری)، ترتیب آرگومان‌ها بسیار مهم است. بیایید آرگومان های نام و سن را در سازنده خود عوض کنیم.
public class Cat {

   String name;
   int age;

   public Cat(int age, String name) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 10); //error!
   }
}
خطا! سازنده به وضوح بیان می کند که وقتی یک شی Cat ایجاد می شود، باید یک عدد و یک رشته به آن ترتیب داده شود. به همین دلیل است که کد ما کار نمی کند. حتماً این را به خاطر داشته باشید و هنگام ایجاد کلاس های خود این را در نظر داشته باشید:
public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
این دو طراح کاملا متفاوت هستند! اگر پاسخ سوال «چرا به سازنده نیاز داریم؟» را در یک جمله بیان کنیم، می‌توان گفت: به طوری که اشیاء همیشه در حالت صحیح باشند. هنگامی که از سازنده ها استفاده می کنید، همه متغیرهای شما به درستی مقداردهی اولیه می شوند و هیچ ماشینی با سرعت 0 یا سایر اشیاء "نادرست" در برنامه وجود نخواهد داشت. استفاده از آنها قبل از هر چیز برای خود برنامه نویس بسیار مفید است. اگر خودتان فیلدها را مقداردهی اولیه کنید، خطر زیادی وجود دارد که چیزی را از دست بدهید و اشتباه کنید. اما این اتفاق با سازنده نمی‌افتد: اگر همه آرگومان‌های مورد نیاز را به آن منتقل نکنید یا انواع آنها را با هم مخلوط نکنید، کامپایلر بلافاصله خطا می‌دهد. قابل ذکر است که نباید منطق برنامه خود را داخل سازنده قرار دهید. برای انجام این کار، شما روش هایی در اختیار دارید که در آنها می توانید تمام عملکردهای مورد نیاز خود را شرح دهید. بیایید ببینیم چرا منطق سازنده ایده بدی است:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called" + this.name);
   System.out.println("She was founded" + this.age + " years ago" );
   System.out.println("During this time it was produced" + this.carsCount +  "cars");
   System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
ما یک کلاس CarFactory داریم که کارخانه تولید خودرو را توصیف می کند. در داخل سازنده، تمام فیلدها را مقداردهی اولیه می کنیم و منطق را در اینجا قرار می دهیم: برخی از اطلاعات مربوط به کارخانه را به کنسول نمایش می دهیم. به نظر می رسد هیچ مشکلی در این مورد وجود ندارد، برنامه کاملاً کار می کرد. خروجی کنسول:
کارخانه خودروسازی ما فورد نام دارد که 115 سال پیش تاسیس شد و در این مدت 50000000 خودرو تولید کرده و به طور متوسط ​​سالانه 434782 خودرو تولید می کند.
اما در واقع ما یک بمب ساعتی کار گذاشته ایم. و چنین کدهایی به راحتی می تواند منجر به خطا شود. بیایید تصور کنیم که اکنون صحبت از فورد نیست، بلکه در مورد کارخانه جدید "آمیگو موتورز" است که کمتر از یک سال است که وجود دارد و 1000 خودرو تولید کرده است:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called" + this.name);
   System.out.println("She was founded" + this.age + " years ago" );
   System.out.println("During this time it was produced" + this.carsCount +  "cars");
   System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
خروجی کنسول:
کارخانه خودروسازی ما Amigo Motors Exception در موضوع "اصلی" java.lang نامیده می شود.ArithmeticException: / توسط صفر 0 سال پیش تاسیس شد در این مدت، 1000 خودرو در CarFactory تولید کرد.<init>(CarFactory.java:15) در CarFactory.main(CarFactory.java:23) فرآیند با کد خروج 1 به پایان رسید</init>
ما رسیدیم! این برنامه با یک خطای عجیب به پایان رسید. آیا سعی می کنید حدس بزنید دلیل چیست؟ دلیلش هم منطقی است که در سازنده قرار دادیم. به طور مشخص در این خط:
System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
در اینجا ما محاسبه را انجام می دهیم و تعداد خودروهای تولید شده را بر سن کارخانه تقسیم می کنیم. و از آنجایی که کارخانه ما جدید است (یعنی 0 ساله است) نتیجه تقسیم بر 0 است که در ریاضیات ممنوع است. در نتیجه برنامه با یک خطا خاتمه می یابد. باید چیکار میکردیم؟ تمام منطق را به یک متد جداگانه منتقل کنید و آن را به عنوان مثال printFactoryInfo() صدا بزنید . می توانید آن را به عنوان یک آبجکت CarFactory به عنوان پارامتر ارسال کنید . شما همچنین می توانید تمام منطق را در آنجا قرار دهید، و در عین حال - خطاهای احتمالی را پردازش کنید، مانند ما با سال صفر. به هر کدام مال خودش سازندگان برای تنظیم صحیح وضعیت یک شی مورد نیاز هستند. برای منطق کسب و کار ما روش هایی داریم. شما نباید یکی را با دیگری مخلوط کنید.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION