Buku "Benda elegan. Edisi Jawa Β»

gambar Hai, habrozhiteli! Buku ini secara serius merevisi esensi dan prinsip-prinsip pemrograman berorientasi objek (OOP) dan dapat secara metaforis disebut "Lobachevsky OOP". Egor Bugaenko , seorang pengembang dengan pengalaman 20 tahun, secara kritis menganalisis dogma-dogma OOP dan menawarkan untuk melihat paradigma ini dengan cara yang sepenuhnya baru. Jadi, dia menstigma metode statis, getter, setter, metode bisa berubah, percaya bahwa ini adalah kejahatan. Untuk seorang programmer pemula, buku ini bisa menjadi pencerahan atau kejutan, dan bagi seorang programmer yang berpengalaman itu adalah bacaan wajib.

Kutipan β€œJangan Menggunakan Metode Statis”


Ah, metode statis ... Salah satu topik favorit saya. Saya perlu beberapa tahun untuk menyadari betapa pentingnya masalah ini. Sekarang saya menyesal sepanjang waktu karena saya habiskan menulis perangkat lunak prosedural daripada berorientasi objek. Saya buta, tetapi sekarang saya telah melihat. Metode statis sama besar jika bahkan bukan masalah yang lebih besar dalam OOP daripada memiliki konstanta NULL. Metode statis, pada prinsipnya, seharusnya tidak di Jawa, dan dalam bahasa berorientasi objek lainnya, tetapi, sayangnya, mereka ada di sana. Kita seharusnya tidak tahu tentang hal-hal seperti kata kunci statis di Jawa, tetapi, sayangnya, dipaksakan .. Saya tidak tahu siapa yang membawanya ke Jawa, tetapi itu benar-benar jahat .. Metode statis, bukan penulis fitur ini. Saya harap begitu.

Mari kita lihat apa metode statis dan mengapa kita masih membuatnya. Katakanlah saya memerlukan fungsionalitas memuat halaman web melalui permintaan HTTP. Saya membuat "kelas" seperti itu:

class WebPage { public static String read(String uri) { //  HTTP- //     UTF8- } } 

Sangat nyaman untuk menggunakannya:

 String html = WebPage.read("http://www.java.com"); 

Metode read () milik kelas metode yang saya menentang. Saya sarankan menggunakan objek sebagai gantinya (saya juga mengubah nama metode sesuai dengan rekomendasi dari bagian 2.4):

 class WebPage { private final String uri; public String content() { //  HTTP- //     UTF8- } } 

Berikut cara menggunakannya:

 String html = new WebPage("http://www.java.com") .content(); 

Anda dapat mengatakan bahwa tidak ada banyak perbedaan di antara mereka. Metode statis bekerja lebih cepat karena kita tidak perlu membuat objek baru setiap kali kita perlu mengunduh halaman web. Panggil saja metode statis, itu akan melakukan pekerjaan, Anda akan mendapatkan hasilnya dan akan terus bekerja .. Tidak perlu dipusingkan dengan benda dan pengumpul sampah. Selain itu, kita dapat mengelompokkan beberapa metode statis ke dalam kelas utilitas dan menamainya, katakanlah, WebUtils.

Metode ini akan membantu memuat halaman web, mendapatkan informasi statistik, menentukan waktu respons, dll. Akan ada banyak metode di dalamnya, dan menggunakannya sederhana dan intuitif. Selain itu, cara menerapkan metode statis juga intuitif. Semua orang mengerti bagaimana mereka bekerja. Cukup tulis WebPage.read (), dan - Anda dapat menebaknya! - halaman akan dibaca. Kami memberikan instruksi komputer, dan menjalankannya .. Sederhana dan jelas, bukan? Dan tidak!

Metode statis dalam konteks apa pun adalah indikator yang jelas dari seorang programmer yang buruk yang tidak tahu tentang OOP. Tidak ada pembenaran untuk menerapkan metode statis dalam situasi apa pun. Merawat kinerja tidak masuk hitungan. Metode statis adalah penghinaan terhadap paradigma berorientasi objek. Mereka ada di Java, Ruby, C ++, PHP dan bahasa lainnya. Sayangnya Kami tidak dapat membuangnya, kami tidak dapat menulis ulang semua pustaka sumber terbuka yang penuh dengan metode statis, tetapi kami dapat berhenti menggunakannya dalam kode kami.

Kita harus berhenti menggunakan metode statis.

Sekarang mari kita lihat mereka dari beberapa posisi berbeda dan diskusikan kekurangan praktisnya. Saya dapat menyamaratakannya terlebih dahulu kepada Anda: metode statis menurunkan pemeliharaan perangkat lunak. Ini seharusnya tidak mengejutkan Anda. Semuanya berujung pada pemeliharaan.

Berpikir Objektif versus Komputer


Awalnya, saya menyebut subbab ini Objective versus Prosedural Thinking, tetapi kemudian menamainya. "Berpikir prosedural" berarti hal yang hampir sama, tetapi frasa "berpikir seperti komputer" menggambarkan masalah dengan lebih baik. Kami mewarisi cara berpikir ini dari bahasa pemrograman awal seperti Assembly, C, COBOL, Basic, Pascal, dan banyak lainnya. Dasar dari paradigma itu adalah bahwa komputer bekerja untuk kita, dan kita memberitahunya apa yang harus dilakukan, memberinya instruksi eksplisit, misalnya:

  CMP AX, BX JNAE greater MOV CX, BX RET greater: MOV CX, AX RET 

Ini adalah assembler "rutin" untuk prosesor Intel 8086. Ia menemukan dan mengembalikan yang lebih besar dari dua angka. Kami menempatkan mereka di register AX dan BX, masing-masing, dan hasilnya jatuh ke register CX. Berikut adalah kode C yang sama persis:

 int max(int a, int b) { if (a > b) { return a; } return b; } 

"Apa yang salah dengan itu?" - kamu bertanya. Tidak ada .. Semuanya baik-baik saja dengan kode ini - ini berfungsi sebagaimana mestinya. Itulah cara semua komputer bekerja. Mereka mengharapkan kami untuk memberi mereka instruksi bahwa mereka akan mengikuti satu demi satu .. Selama bertahun-tahun kami menulis program dengan cara ini. Keuntungan dari pendekatan ini adalah kita tetap dekat dengan prosesor, mengarahkan pergerakan selanjutnya. Kami di pucuk pimpinan, dan komputer mengikuti instruksi kami. Kami memberi tahu komputer cara menemukan yang lebih besar dari dua angka. Kami membuat keputusan, dia mengikuti mereka. Alur eksekusi selalu konsisten, dari awal skrip hingga akhir.

Jenis pemikiran linier ini disebut "berpikir seperti komputer." Komputer pada titik tertentu mulai menjalankan instruksi dan pada titik tertentu selesai melakukannya. Saat menulis kode dalam C, kita dipaksa untuk berpikir seperti ini. Operator yang dipisahkan oleh titik koma bergerak dari atas ke bawah. Gaya ini diwarisi dari assembler.
Meskipun bahasa pada tingkat yang lebih tinggi daripada assembler memiliki prosedur, subrutin, dan mekanisme abstraksi lainnya, mereka tidak menghilangkan cara berpikir yang konsisten. Program ini masih berjalan dari atas ke bawah. Tidak ada yang salah dengan pendekatan seperti itu ketika menulis program kecil, tetapi dalam skala yang lebih besar sulit untuk berpikir seperti itu.

Lihatlah kode yang sama yang ditulis dalam bahasa pemrograman fungsional Lisp:

 (defun max (ab) (if (> ab) ab)) 

Bisakah Anda tahu di mana eksekusi kode ini dimulai dan berakhir? Tidak. Kami tidak tahu bagaimana prosesor akan mendapatkan hasilnya, atau bagaimana fungsi if akan bekerja. Kami sangat jauh dari prosesor. Kami berpikir sebagai fungsi, bukan sebagai komputer. Ketika kita membutuhkan hal baru, kita mendefinisikannya:

 (def x (max 5 9)) 

Kami mendefinisikan, tidak memberikan instruksi kepada prosesor. Dengan baris ini kita mengikat x ke (maks 5 9). Kami tidak meminta komputer untuk menghitung yang lebih besar dari dua angka. Kami hanya mengatakan bahwa x adalah yang lebih besar dari dua angka. Kami tidak mengontrol bagaimana dan kapan akan dihitung. Perhatikan ini penting: x adalah angka yang lebih besar. Relasi "is" ("to be", "to be") adalah perbedaan antara paradigma pemrograman fungsional, logis, dan berorientasi objek dari yang prosedural.

Dengan pola pikir komputer, kita berada di pucuk pimpinan dan mengendalikan aliran instruksi. Dengan cara berpikir berorientasi objek, kita hanya menentukan siapa itu siapa, dan membiarkan mereka berinteraksi ketika mereka membutuhkannya. Begini cara menghitung yang lebih besar dari dua angka akan terlihat seperti di OOP:

 class Max implements Number { private final Number a; private final Number b; public Max(Number left, Number right) { this.a = left; this.b = right; } } 

Jadi saya akan menggunakannya:

 Number x = new Max(5, 9); 

Dengar, saya tidak menghitung yang lebih besar dari dua angka. Saya menentukan bahwa x adalah yang lebih besar dari dua angka. Saya tidak peduli apa yang ada di dalam objek kelas Max dan bagaimana tepatnya mengimplementasikan antarmuka Angka. Saya tidak memberikan instruksi prosesor mengenai perhitungan ini. Saya hanya instantiate objek. Ini sangat mirip dengan def di Lisp .. Dalam hal ini, OOP sangat mirip dengan pemrograman fungsional.

Sebaliknya, metode statis dalam OOP sama dengan subrutin dalam C atau assembler. Mereka tidak terkait dengan OOP dan memaksa kita untuk menulis kode prosedural dalam sintaks berorientasi objek. Berikut adalah kode Java:

 int x = Math.max(5, 9); 

Ini sepenuhnya salah dan tidak boleh digunakan dalam desain berorientasi objek nyata.

Gaya deklaratif versus imperatif


Pemrograman imperatif "menggambarkan perhitungan dalam hal operator yang mengubah keadaan suatu program" .. Pemrograman deklaratif, di sisi lain, "mengekspresikan logika komputasi tanpa menggambarkan aliran pelaksanaannya" (saya kutip Wikipedia). Kami, pada kenyataannya, membicarakan hal ini selama beberapa halaman sebelumnya. Pemrograman imperatif mirip dengan yang dilakukan komputer - menjalankan instruksi secara berurutan. Pemrograman deklaratif lebih dekat dengan cara berpikir alami di mana kita memiliki entitas dan hubungan di antara mereka. Jelas, pemrograman deklaratif adalah pendekatan yang lebih kuat, tetapi pendekatan imperatif lebih mudah dipahami oleh programmer prosedural. Mengapa pendekatan deklaratif lebih kuat? Jangan beralih, dan setelah beberapa halaman kita sampai pada intinya.

Apa hubungannya semua ini dengan metode statis? Tidak masalah apakah itu metode atau objek statis, kita masih harus menulis jika (a> b) di suatu tempat, kan? Ya persis. Baik metode statis dan objek hanyalah pembungkus pada pernyataan if, yang melakukan tugas membandingkan a dengan b. Perbedaannya adalah bagaimana fungsi ini digunakan oleh kelas, objek, dan metode lain. Dan ini perbedaan yang signifikan. Pertimbangkan itu dengan sebuah contoh.
Katakanlah saya memiliki interval terbatas pada dua bilangan bulat, dan bilangan bulat yang harus jatuh ke dalamnya .. Saya harus memastikan bahwa itu. Inilah yang harus saya lakukan jika metode max () statis:

 public static int between(int l, int r, int x) { return Math.min(Math.max(l, x), r); } 

Kita perlu membuat metode statis lain, antara (), yang menggunakan dua metode statis yang tersedia, Math.min () dan Math.max (). Hanya ada satu cara untuk melakukan ini - pendekatan imperatif, karena nilainya dihitung segera. Ketika saya melakukan panggilan, saya segera mendapatkan hasilnya:

 int y = Math.between(5, 9, 13); //  9 

Saya mendapatkan nomor 9 tepat setelah menelepon antara (). Ketika panggilan dibuat, prosesor saya akan segera mulai bekerja pada perhitungan ini. Ini adalah pendekatan imperatif. Lalu seperti apa pendekatan deklaratif itu?

Di sini, lihat:

 class Between implements Number { private final Number num; Between(Number left, Number right, Number x) { this.num = new Min(new Max(left, x), right); } @Override public int intValue() { return this.num.intValue(); } } 

Beginilah cara saya akan menggunakannya:

 Number y = new Between(5, 9, 13); //   ! 

Rasakan bedanya? Dia sangat penting. Gaya ini akan deklaratif, karena saya tidak memberi tahu prosesor bahwa perhitungan harus segera dilakukan. Saya baru saja menentukan apa itu dan menyerahkannya kepada pengguna untuk memutuskan kapan (dan apakah perlu sama sekali) untuk menghitung variabel y menggunakan metode intValue (). Mungkin itu tidak akan pernah dihitung dan prosesor saya tidak akan pernah tahu apa angka 9 .. Yang saya lakukan hanyalah menyatakan apa y. Baru diumumkan. Saya belum memberikan pekerjaan kepada prosesor. Seperti ditunjukkan dalam definisi, logika dinyatakan tanpa menggambarkan proses.

Saya sudah mendengar: "Oke, saya mengerti Anda. Ada dua pendekatan - deklaratif dan prosedural, tetapi mengapa yang pertama lebih baik dari yang kedua? " Saya sebutkan sebelumnya bahwa jelas bahwa pendekatan deklaratif lebih kuat, tetapi tidak menjelaskan mengapa. Sekarang kita telah memeriksa kedua pendekatan dengan contoh, kita akan membahas keuntungan dari pendekatan deklaratif.

Pertama, lebih cepat. Sekilas, mungkin terlihat lebih lambat. Tetapi jika Anda melihat lebih dekat, akan menjadi jelas bahwa sebenarnya lebih cepat, karena optimalisasi kinerja sepenuhnya ada di tangan kami. Memang, akan membutuhkan waktu lebih lama untuk membuat instance dari kelas Antara daripada memanggil metode statis antara (), setidaknya di sebagian besar bahasa pemrograman yang tersedia pada saat menulis buku ini .. Saya sangat berharap bahwa kita akan memiliki bahasa dalam waktu dekat di mana instantiating objek akan secepat memanggil metode. Tetapi kita belum datang kepadanya. Itulah sebabnya pendekatan deklaratif lebih lambat ... ketika jalur eksekusi sederhana dan mudah.

Jika kita berbicara tentang panggilan sederhana ke metode statis, maka itu pasti akan lebih cepat daripada membuat instance objek dan memanggil metode-metodenya. Tetapi jika kita memiliki banyak metode statis, mereka akan dipanggil secara berurutan ketika menyelesaikan masalah, dan tidak hanya bekerja pada hasil yang benar-benar kita butuhkan. Bagaimana dengan ini:

 public void doIt() { int x = Math.between(5, 9, 13); if (/*  ? */) { System.out.println("x=" + x); } } 

Dalam contoh ini, kita menghitung x terlepas dari apakah kita memerlukan nilainya atau tidak .. Prosesor akan menemukan nilai 9 dalam kedua kasus. Apakah metode selanjutnya menggunakan pendekatan deklaratif bekerja secepat yang sebelumnya?

 public void doIt() { Integer x = new Between(5, 9, 13); if (/*  ? */) { System.out.println("x=" + x); } } 

Saya pikir kode deklaratif akan lebih cepat. Lebih baik dioptimalkan. Dan itu tidak memberi tahu prosesor apa yang harus dilakukan. Sebaliknya, itu memungkinkan prosesor untuk memutuskan kapan dan di mana hasilnya benar-benar diperlukan - perhitungan dilakukan sesuai permintaan.

Intinya adalah bahwa pendekatan deklaratif lebih cepat karena optimal. Ini adalah argumen pertama yang mendukung pendekatan deklaratif dibandingkan dengan imperatif dalam pemrograman berorientasi objek. Gaya imperatif jelas tidak memiliki tempat di OOP, dan alasan pertama untuk ini adalah pengoptimalan kinerja .. Anda tidak boleh mengatakan bahwa semakin Anda mengontrol pengoptimalan kode, semakin banyak yang diikuti. Alih-alih menyerahkan optimisasi proses perhitungan ke kompiler, mesin virtual, atau prosesor, kami melakukannya sendiri.

Argumen kedua adalah polimorfisme. Sederhananya, polimorfisme adalah kemampuan untuk memecah ketergantungan antara blok kode. Misalkan saya ingin mengubah algoritma untuk menentukan apakah suatu angka jatuh dalam interval tertentu. Itu cukup primitif dalam dirinya sendiri, tetapi saya ingin mengubahnya. Saya tidak ingin menggunakan kelas Max dan Min. Dan saya ingin dia melakukan perbandingan menggunakan pernyataan if-then-else .. Inilah cara melakukannya secara deklaratif:

 class Between implements Number { private final Number num; Between(int left, int right, int x) { this(new Min(new Max(left, x), right)); } Between(Number number) { this.num = number; } } 

Ini sama antara kelas seperti pada contoh sebelumnya, tetapi dengan konstruktor tambahan. Sekarang saya bisa menggunakannya dengan algoritma lain:

 Integer x = new Between( new IntegerWithMyOwnAlgorithm(5, 9, 13) ); 

Ini mungkin bukan contoh terbaik, karena kelas Antar sangat primitif, tapi saya harap Anda mengerti apa yang saya maksud. Kelas antar sangat mudah dipisahkan dari kelas Max dan Min, karena mereka adalah kelas. Dalam pemrograman berorientasi objek, objek adalah warga negara penuh, tetapi metode statis tidak. Kita dapat meneruskan objek sebagai argumen ke konstruktor, tetapi kita tidak dapat melakukan hal yang sama dengan metode statis. Dalam OOP, objek dikaitkan dengan objek, berkomunikasi dengan objek, dan bertukar data dengan mereka. Untuk sepenuhnya melepaskan objek dari objek lain, kita harus memastikan bahwa itu tidak menggunakan operator baru dalam salah satu metodenya (lihat bagian 3.6), serta di konstruktor utama.

Saya ulangi: untuk sepenuhnya melepaskan objek dari objek lain, Anda hanya perlu memastikan bahwa operator baru tidak digunakan dalam salah satu metodenya, termasuk konstruktor utama.

Bisakah Anda melakukan decoupling dan refactoring yang sama dengan cuplikan kode imperatif?

 int y = Math.between(5, 9, 13); 

Tidak, kamu tidak bisa. Metode statis antara () menggunakan dua metode statis, min () dan maks (), dan Anda tidak dapat melakukan apa pun hingga Anda menulis ulang sepenuhnya. Dan bagaimana Anda bisa menulis ulang? Lewati parameter keempat ke metode statis baru?

Seberapa jelek tampilannya? Saya pikir sangat.

Berikut adalah argumen kedua saya yang mendukung gaya pemrograman deklaratif - mengurangi kohesi objek dan membuatnya sangat elegan .. Belum lagi fakta bahwa kohesi yang kurang berarti lebih banyak rawatan.

Argumen ketiga yang mendukung keunggulan pendekatan deklaratif atas imperatif - pendekatan deklaratif berbicara tentang hasilnya, sementara imperatif menjelaskan satu-satunya cara untuk mendapatkannya. Pendekatan kedua jauh kurang intuitif daripada yang pertama. Saya pertama-tama harus "mengeksekusi" kode di kepala saya untuk memahami hasil yang diharapkan. Berikut ini adalah pendekatan imperatif:

 Collection<Integer> evens = new LinkedList<>(); for (int number : numbers) { if (number % 2 == 0) { evens.add(number); } } 

Untuk memahami apa yang kode ini lakukan, saya harus melewatinya, memvisualisasikan siklus ini .. Bahkan, saya harus melakukan apa yang dilakukan prosesor - menelusuri seluruh array angka dan memasukkan angka genap dalam daftar baru. Berikut adalah algoritma yang sama, yang ditulis dalam gaya deklaratif:

 Collection<Integer> evens = new Filtered( numbers, new Predicate<Integer>() { @Override public boolean suitable(Integer number) { return number % 2 == 0; } } ); 

Potongan kode ini jauh lebih dekat dengan bahasa Inggris daripada yang sebelumnya. Bunyinya sebagai berikut: "evens adalah kumpulan yang difilter yang hanya mencakup elemen-elemen yang genap." Saya tidak tahu persis bagaimana kelas yang difilter membuat koleksi - apakah ia menggunakan pernyataan for atau yang lainnya. Yang perlu saya ketahui saat membaca kode ini adalah bahwa koleksi telah disaring. Detail implementasi disembunyikan, dan perilaku diungkapkan.

Saya menyadari bahwa bagi sebagian pembaca buku ini, lebih mudah untuk memahami fragmen pertama .. Agak lebih pendek dan sangat mirip dengan apa yang Anda lihat setiap hari dalam kode yang Anda hadapi. Saya yakinkan Anda bahwa ini adalah masalah kebiasaan. Ini adalah perasaan menipu. Mulailah berpikir dalam hal objek dan perilaku mereka, alih-alih algoritma dan eksekusi mereka, dan Anda akan mendapatkan persepsi yang benar. Gaya deklaratif secara langsung berkaitan dengan objek dan perilaku mereka, dan keharusan - untuk algoritma dan pelaksanaannya.

Jika Anda menemukan kode ini jelek, coba Groovy, misalnya:

 def evens = new Filtered( numbers, { Integer number -> number % 2 == 0 } ); 

Argumen keempat adalah integritas kode. Lihatlah dua cuplikan sebelumnya. Harap perhatikan bahwa dalam fragmen kedua kami mendeklarasikan evens sebagai satu operator - evens = Filtered (...). Ini berarti bahwa semua baris kode yang bertanggung jawab untuk menghitung koleksi ini bersebelahan dan tidak dapat dipisahkan secara keliru. Sebaliknya, dalam fragmen pertama tidak ada "pengeleman" garis yang jelas. Anda dapat dengan mudah mengubah urutannya secara tidak sengaja, dan algoritme akan rusak.

Sedemikian sederhana kode, ini adalah masalah kecil, karena algoritme jelas. Tetapi jika fragmen kode imperatif lebih besar - katakanlah, 50 baris, mungkin sulit untuk memahami baris kode mana yang terkait satu sama lain. , karena rawatan yang ditingkatkan.

Mungkin masih ada argumen, tetapi saya telah mengutip yang paling penting, dari sudut pandang saya, yang terkait dengan OOP. Saya harap saya bisa meyakinkan Anda bahwa gaya deklaratif adalah yang Anda butuhkan. Beberapa dari Anda mungkin berkata, β€œYa, saya mengerti maksud Anda. Saya akan menggabungkan pendekatan deklaratif dan imperatif yang sesuai. Saya akan menggunakan objek yang masuk akal, dan metode statis ketika saya perlu dengan cepat melakukan sesuatu yang sederhana, seperti menghitung dua angka yang lebih besar. ".." Tidak, Anda salah! " - Saya akan menjawab Anda. Anda tidak boleh mengkombinasikannya .. Jangan pernah menggunakan gaya imperatif. Ini bukan dogma .. Ini memiliki penjelasan yang sangat pragmatis.

Gaya imperatif tidak dapat dikombinasikan dengan deklaratif murni teknis. , β€” .

, β€” max() min(). , . , , .. β€” Between, between(). ? , , , , . . , Between. , - , .

- : , β€” . .

Β« ! β€” . β€” ?Β» … , . - , - ( ). , , β€” . , .. , . , , β€” , , , . , Apache Commons FileUtils.readLines(), . :

 class FileLines implements Iterable<String> { private final File file; public Iterator<String> iterator() { return Arrays.asList( FileUtils.readLines(this.file) ).iterator(); } } 

, , :

 Iterable<String> lines = new FileLines(f); 

FileLines, . . , , β€” FileLines. , .

-


- , , ( -).. , java.lang.Math β€” -. Java, Ruby , , . ? . 1.1 , β€” . - , :

 class Math { private Math() { //   } public static int max(int a, int b) { if (a < b) { return b; } return a; } } 

, -, , , . , , , .

- β€” - . - β€” β€” . , , . - β€” .. .

«»


«» β€” , , . , , . :

 class Math { private static Math INSTANCE = new Math(); private Math() {} public static Math getInstance() { return Math.INSTANCE; } public int max(int a, int b) { if (a < b) { return b; } return a; } } 

. Math, INSTANCE.. , getInstance(). , . INSTANCE β€” getInstance().

«» , . , . , . , , , , -, . - Math, , :

 class Math { private Math() {} public static int max(int a, int b) { if (a < b) { return b; } return a; } } 

max():

 Math.max(5, 9); // - Math.getInstance().max(5, 9); //  

? , , . , -? Java-. , : Β« Β». Sebagai contoh:

 class User { private static User INSTANCE = new User(); private String name; private User() {} public static User getInstance() { return User.INSTANCE; } public String getName() { return this.name; } public String setName(String txt) { this.name = txt; } } 

, . Β«, Β». -, , - . .. , -: Β« Β».. . .. -, , :

 class User { private static String name; private User() {} public static String getName() { return User.name; } public static String setName(String txt) { User.name = txt; } } 

- , . , ? ? , β€” , , - β€” , . , , setInstance() getInstance(). , . , :

 Math.getInstance().max(5, 9); 

Math. , Math β€” , . , Math , . , . , , , -, . , , Math.max() -. ? :

 Math math = new FakeMath(); Math.setInstance(math); 

«» , . : - , . - β€” . - β€” β€” .

, ? -, , . Mengapa , β€” , , .. . . , :

 #include <stdio> int line = 0; void echo(char* text) { printf("[%d] %s\n", ++line, text); } 

echo(), line. line *.-.. . Java , . Java, Ruby --, . Mengapa . . . . , . , , GOTO.

, , - Java, «».. - , . .
. .

Β« ? β€” . β€” , , ?Β» , , , . - . ? !

, .

, , .. . . , . , : , , . . , , , . , β€” , 2.1.

. .


: , ()? , , , .. , ? Lisp, Clojure Haskell Java C++?

, :

 class Max implements Number { private final int a; private final int b; public Max(int left, int right) { this.a = left; this.b = right; } @Override public int intValue() { return this.a > this.b ? this.a : this.b; } } 

:

 Number x = new Max(5, 9); 

Lisp , :

 (defn max (ab) (if (> ab) ab)) 

, ? Lisp .

, , β€” . - , - -, . , - Java, , Java , -. β€” , . .

, - . -, Java, ( ) , . .


, . β€” - . β€” - , β€” , , :

 names = new Sorted( new Unique( new Capitalized( new Replaced( new FileNames( new Directory( "/var/users/*.xml" ) ), "([^.]+)\\.xml", "$1" ) ) ) ); 

, , -. , 3.2. , names, , , . , , , . .

? , , , .

, . Directory, FileNames, Replaced, Capitalized, Unique Sorted β€” , . . .

, ( ). , Unique β€” Iterable, . FileNames β€” , .
- . , .. - app.run(), . if, for, switch while. , .

if Java , . Java , If? :

 float rate; if (client.age() > 65){ rate = 2.5; } else { rate = 3.0; } 

- :

 float rate = new If( client.age() > 65, 2.5, 3.0 ); 

?

 float rate = new If( new Greater(client.age(), 65), 2.5, 3.0 ); 

, :

 float rate = new If( new GreaterThan( new AgeOf(client), 65 ), 2.5, 3.0 ); 

- . β€” , rate.

, , . if, for, switch while. If, For, Switch While. ?

, . . . , .. , .
, - β€” .

? , : . , . . . , β€” .

: static β€” , , .

Β»Informasi lebih lanjut tentang buku ini dapat ditemukan di situs web penerbit

20% β€” Java

Source: https://habr.com/ru/post/id418157/


All Articles