Pertanyaan Bagaimana cara multimetode memecahkan masalah namespace?


Saya sedang meneliti desain bahasa pemrograman, dan saya tertarik pada pertanyaan tentang bagaimana mengganti paradigma OO pesan-passing pengiriman pesan yang populer dengan paradigma fungsi generik multimethod. Untuk sebagian besar, tampaknya sangat mudah, tetapi saya baru-baru ini menjadi mandek dan akan sangat menghargai bantuan.

Pesan lewat OO, dalam pikiran saya, adalah salah satu solusi yang menyelesaikan dua berbeda masalah. Saya jelaskan apa yang saya maksud dengan detail dalam pseudocode berikut.

(1) Ini memecahkan masalah pengiriman:

=== dalam file animal.code ===

   - Animals can "bark"
   - Dogs "bark" by printing "woof" to the screen.
   - Cats "bark" by printing "meow" to the screen.

=== dalam file myprogram.code ===

import animal.code
for each animal a in list-of-animals :
   a.bark()

Dalam masalah ini, "kulit kayu" adalah salah satu metode dengan beberapa "cabang" yang beroperasi secara berbeda tergantung pada jenis argumen. Kami menerapkan "kulit kayu" sekali untuk setiap jenis argumen yang kami minati (Anjing dan Kucing). Pada saat runtime, kami dapat melakukan iterasi melalui daftar hewan dan secara dinamis memilih cabang yang tepat untuk diambil.

(2) Ini memecahkan masalah namespace:

=== dalam file animal.code ===

   - Animals can "bark"

=== di file tree.code ===

   - Trees have "bark"

=== dalam file myprogram.code ===

import animal.code
import tree.code

a = new-dog()
a.bark() //Make the dog bark

…

t = new-tree()
b = t.bark() //Retrieve the bark from the tree

Dalam masalah ini, "kulit kayu" sebenarnya adalah dua fungsi yang berbeda secara konseptual terjadi untuk memiliki nama yang sama. Jenis argumen (apakah anjing atau pohon) menentukan fungsi mana yang sebenarnya kita maksud.


Multimethods elegan memecahkan masalah nomor 1. Tapi saya tidak mengerti bagaimana mereka memecahkan masalah nomor 2. Sebagai contoh, yang pertama dari dua contoh di atas dapat diterjemahkan secara langsung ke multimetode:

(1) Anjing dan Kucing menggunakan multimethods

=== dalam file animal.code ===

   - define generic function bark(Animal a)
   - define method bark(Dog d) : print("woof")
   - define method bark(Cat c) : print("meow")

=== dalam file myprogram.code ===

import animal.code
for each animal a in list-of-animals :
   bark(a)

Kuncinya adalah bahwa metode kulit (Anjing) secara konseptual terkait dengan kulit kayu (Cat). Contoh kedua tidak memiliki atribut ini, itulah mengapa saya tidak mengerti bagaimana multimethods memecahkan masalah namespace.

(2) Mengapa metode multimetode tidak berhasil untuk Hewan dan Pohon

=== dalam file animal.code ===

   - define generic function bark(Animal a)

=== di file tree.code ===

   - define generic function bark(Tree t)

=== dalam file myprogram.code ===

import animal.code
import tree.code

a = new-dog()
bark(a)   /// Which bark function are we calling?

t = new-tree
bark(t)  /// Which bark function are we calling?

Dalam hal ini, di mana fungsi generik harus didefinisikan? Haruskah itu didefinisikan di tingkat atas, di atas hewan dan pohon? Tidak masuk akal untuk berpikir tentang kulit kayu dan pohon sebagai dua metode dari fungsi generik yang sama karena dua fungsi secara konseptual berbeda.

Sejauh yang saya tahu, saya belum menemukan pekerjaan sebelumnya yang memecahkan masalah ini. Saya telah melihat multimetoda Clojure, dan metode multimethod CLOS dan mereka memiliki masalah yang sama. Saya menyilangkan jari-jemari saya dan berharap ada solusi elegan untuk masalah ini, atau sebuah argumen meyakinkan tentang mengapa itu sebenarnya bukan masalah dalam pemrograman nyata.

Tolong beri tahu saya jika pertanyaannya membutuhkan klarifikasi. Ini adalah titik yang cukup halus (tapi penting) menurut saya.


Terima kasih atas balasan kewarasan, Rainer, Marcin, dan Matthias. Saya memahami balasan Anda dan sepenuhnya setuju bahwa pengiriman dinamis dan resolusi namespace adalah dua hal yang berbeda. CLOS tidak menyatukan dua ide, sedangkan OO tradisional yang melaluinya. Ini juga memungkinkan untuk perluasan multimethods secara langsung ke multiple inheritance.

Pertanyaan saya secara khusus adalah dalam situasi ketika terjadi pembauran diinginkan.

Berikut ini adalah contoh dari apa yang saya maksud.

=== file: XYZ.code ===

define class XYZ :
   define get-x ()
   define get-y ()
   define get-z ()

=== file: POINT.code ===

define class POINT :
   define get-x ()
   define get-y ()

=== file: GENE.code ===

define class GENE :
   define get-x ()
   define get-xx ()
   define get-y ()
   define get-xy ()

==== file: my_program.code ===

import XYZ.code
import POINT.code
import GENE.code

obj = new-xyz()
obj.get-x()

pt = new-point()
pt.get-x()

gene = new-point()
gene.get-x()

Karena penggabungan resolusi namespace dengan pengiriman, programmer dapat secara naif memanggil get-x () pada ketiga objek. Ini juga tidak ambigu. Setiap objek "memiliki" set metode sendiri, sehingga tidak ada kebingungan tentang apa yang dimaksud programmer.

Bandingkan ini dengan versi multimetode:


=== file: XYZ.code ===

define generic function get-x (XYZ)
define generic function get-y (XYZ)
define generic function get-z (XYZ)

=== file: POINT.code ===

define generic function get-x (POINT)
define generic function get-y (POINT)

=== file: GENE.code ===

define generic function get-x (GENE)
define generic function get-xx (GENE)
define generic function get-y (GENE)
define generic function get-xy (GENE)

==== file: my_program.code ===

import XYZ.code
import POINT.code
import GENE.code

obj = new-xyz()
XYZ:get-x(obj)

pt = new-point()
POINT:get-x(pt)

gene = new-point()
GENE:get-x(gene)

Karena get-x () XYZ tidak memiliki hubungan konseptual untuk mendapatkan-x () GENE, mereka diimplementasikan sebagai fungsi generik yang terpisah. Oleh karena itu, programmer akhir (di my_program.code) harus secara eksplisit memenuhi syarat get-x () dan beri tahu sistem yang get-x () dia sebenarnya bermaksud menelepon.

Memang benar bahwa pendekatan eksplisit ini lebih jelas dan mudah digeneralisasikan ke banyak pengiriman dan multiple inheritance. Tetapi menggunakan (menyalahgunakan) pengiriman untuk memecahkan masalah namespace adalah fitur yang sangat mudah dari pesan-lewat OO.

Saya pribadi merasa bahwa 98% dari kode saya sendiri cukup diekspresikan menggunakan pengiriman tunggal dan warisan tunggal. Saya menggunakan kenyamanan ini menggunakan pengiriman untuk resolusi namespace jauh lebih banyak daripada saya menggunakan banyak pengiriman, jadi saya enggan menyerah.

Apakah ada cara untuk mendapatkan yang terbaik dari kedua dunia? Bagaimana saya menghindari kebutuhan untuk secara eksplisit mengkualifikasikan panggilan fungsi saya dalam pengaturan multi-metode?


Tampaknya konsensus itu

  • multimethods memecahkan masalah pengiriman tetapi tidak menyerang masalah namespace.
  • fungsi yang berbeda secara konseptual harus memiliki nama berbeda, dan pengguna harus diharapkan untuk secara manual mengkualifikasi mereka.

Saya kemudian percaya bahwa, dalam kasus di mana single-waris tunggal-pengiriman cukup, pesan-lewat OO lebih nyaman daripada fungsi generik.

Kedengarannya seperti ini adalah penelitian terbuka. Jika suatu bahasa menyediakan mekanisme untuk multimetode yang juga dapat digunakan untuk resolusi namespace, apakah itu fitur yang diinginkan?

Saya suka konsep fungsi generik, tetapi saat ini merasa mereka dioptimalkan untuk membuat "hal-hal yang sangat sulit tidak begitu sulit" dengan mengorbankan membuat "hal-hal sepele sedikit mengganggu". Karena sebagian besar kode itu sepele, saya masih percaya ini adalah masalah yang berharga untuk dipecahkan.


32
2018-03-04 07:27


asal


Jawaban:


Pengiriman dinamis dan resolusi namespace adalah dua hal yang berbeda. Di banyak kelas sistem objek juga digunakan untuk ruang nama. Juga perhatikan bahwa sering kali kelas dan namespace terikat pada file. Jadi, sistem objek ini menyatukan setidaknya tiga hal:

  • definisi kelas dengan slot dan metode mereka
  • namespace untuk pengenal
  • unit penyimpanan kode sumber

Common Lisp dan sistem objeknya (CLOS) bekerja secara berbeda:

  • kelas tidak membentuk namespace
  • fungsi dan metode generik bukan milik kelas dan karenanya tidak didefinisikan di dalam kelas
  • fungsi generik didefinisikan sebagai fungsi top-level dan dengan demikian tidak bersarang atau lokal
  • pengidentifikasi untuk fungsi generik adalah simbol
  • simbol memiliki mekanisme namespace mereka sendiri yang disebut paket
  • fungsi generik adalah 'terbuka'. Seseorang dapat menambahkan atau menghapus metode kapan saja
  • fungsi generik adalah objek kelas satu
  • mathods adalah objek kelas satu
  • kelas dan fungsi generik juga tidak digabungkan dengan file. Anda dapat menentukan beberapa kelas dan beberapa fungsi umum dalam satu file atau dalam banyak file yang Anda inginkan. Anda juga dapat menentukan kelas dan metode dari menjalankan kode (sehingga tidak terikat ke file) atau sesuatu seperti REPL (baca eval print loop).

Gaya dalam CLOS:

  • jika suatu fungsi memerlukan pengiriman dinamis dan fungsinya terkait erat, maka gunakan satu fungsi umum dengan metode yang berbeda
  • jika ada banyak fungsi yang berbeda, tetapi dengan nama umum, jangan menempatkannya dalam fungsi generik yang sama. Buat fungsi generik yang berbeda.
  • fungsi generik dengan nama yang sama, tetapi di mana nama dalam paket yang berbeda adalah fungsi generik yang berbeda.

Contoh:

(defpackage "ANIMAL" (:use "CL")) 
(in-package "ANIMAL")

(defclass animal () ())
(deflcass dog (animal) ())
(deflcass cat (animal) ()))

(defmethod bark ((an-animal dog)) (print 'woof))
(defmethod bark ((an-animal cat)) (print 'meow)) 

(bark (make-instance 'dog))
(bark (make-instance 'dog))

Perhatikan bahwa kelas ANIMAL dan paketnya ANIMAL memiliki nama yang sama. Tapi itu tidak perlu demikian. Nama-nama tidak terhubung dengan cara apa pun. DEFMETHOD secara implisit menciptakan fungsi generik yang sesuai.

Jika Anda menambahkan paket lain (misalnya GAME-ANIMALS), lalu BARK fungsi generik akan berbeda. Kecuali paket-paket ini terkait (misalnya satu paket menggunakan yang lain).

Dari paket yang berbeda (simbol namespace di Common Lisp), seseorang dapat memanggil ini:

(animal:bark some-animal)

(game-animal:bark some-game-animal)

Simbol memiliki sintaks

PACKAGE-NAME::SYMBOL-NAME

Jika paketnya sama dengan paket saat ini, maka itu bisa dihilangkan.

  • ANIMAL::BARK mengacu pada simbol yang bernama BARK dalam paket ANIMAL. Perhatikan bahwa ada dua titik dua.
  • AINMAL:BARK mengacu kepada diekspor simbol BARK dalam paket ANIMAL. Perhatikan bahwa hanya ada satu titik dua. Mengekspor, pengimporan dan menggunakan adalah mekanisme yang ditentukan untuk paket dan simbolnya. Jadi mereka tidak bergantung pada kelas dan fungsi generik, tetapi dapat digunakan untuk menyusun namespace untuk simbol yang menamakannya.

Kasus yang lebih menarik adalah ketika multimethods benar-benar digunakan dalam fungsi generik:

(defmethod bite ((some-animal cat) (some-human human))
  ...)

(defmethod bite ((some-animal dog) (some-food bone))
  ...)

Di atas menggunakan kelas CAT, HUMAN, DOG dan BONE. Kelas mana yang seharusnya memiliki fungsi generik? Seperti apa tampilan ruang nama khusus?

Karena fungsi generik mengirimkan semua argumen, itu tidak membuat perasaan langsung untuk mengkonfigurasikan fungsi generik dengan namespace khusus dan membuatnya menjadi definisi dalam satu kelas.

Motivasi:

Fungsi umum ditambahkan pada 80-an ke Lisp oleh pengembang di Xerox PARC (untuk LOOPS umum) dan pada Simbolis untuk Rasa Baru. Satu ingin menyingkirkan mekanisme panggilan tambahan (pesan lewat) dan membawa pengiriman ke fungsi biasa (tingkat atas). Rasa Baru memiliki pengiriman tunggal, tetapi fungsi generik dengan banyak argumen. Penelitian ke dalam LOOPS Umum kemudian membawa banyak pengiriman. Rasa Baru dan LOOPS Umum kemudian digantikan oleh standar CLOS. Ide-ide ini kemudian dibawa ke bahasa lain seperti Dylan.

Karena kode contoh dalam pertanyaan tidak menggunakan fungsi umum apa pun yang ditawarkan, sepertinya seseorang harus mengorbankan sesuatu.

Ketika pengiriman tunggal, pengiriman pesan dan pewarisan tunggal sudah cukup, maka fungsi generik mungkin terlihat seperti langkah mundur. Alasannya adalah, seperti yang disebutkan, bahwa seseorang tidak ingin meletakkan semua jenis fungsi bernama serupa ke dalam satu fungsi umum.

Kapan

(defmethod bark ((some-animal dog)) ...)
(defmethod bark ((some-tree oak)) ...)

terlihat serupa, mereka adalah dua tindakan yang secara konseptual berbeda.

Tetapi lebih lanjut:

(defmethod bark ((some-animal dog) tone loudness duration)
   ...)

(defmethod bark ((some-tree oak)) ...)

Sekarang tiba-tiba daftar parameter untuk fungsi generik bernama yang sama terlihat berbeda. Haruskah itu diizinkan menjadi satu fungsi umum? Jika tidak, bagaimana kita memanggilnya BARK pada berbagai objek dalam daftar hal-hal dengan parameter yang tepat?

Dalam fungsi-fungsi generik kode Lisp yang nyata biasanya terlihat jauh lebih rumit dengan beberapa argumen yang diperlukan dan opsional.

Dalam fungsi umum Common Lisp juga tidak hanya memiliki tipe metode tunggal. Ada berbagai jenis metode dan berbagai cara untuk menggabungkannya. Itu hanya masuk akal untuk menggabungkan mereka, ketika mereka benar-benar milik fungsi generik tertentu.

Karena fungsi generik juga merupakan objek kelas satu, mereka dapat diedarkan, dikembalikan dari fungsi dan disimpan dalam struktur data. Pada titik ini objek fungsi generik itu sendiri adalah penting, bukan namanya lagi.

Untuk kasus sederhana di mana saya memiliki objek, yang memiliki koordinat x dan y dan dapat bertindak sebagai titik, saya akan mewarisi kelas objek dari POINT kelas (mungkin karena beberapa mixin). Lalu saya akan mengimpor GET-X dan GET-Y simbol ke beberapa namespace - jika perlu.

Ada bahasa lain yang lebih berbeda dari Lisp / CLOS dan yang mencoba (ed) untuk mendukung multimetode:

Sepertinya ada banyak upaya untuk menambahkannya ke Java.


19
2018-03-04 08:35



Contoh Anda untuk "Mengapa multimethod tidak berfungsi" menganggap Anda dapat mendefinisikan dua fungsi generik yang bernama identik dalam namespace bahasa yang sama. Ini umumnya tidak terjadi; misalnya, multimetode Clojure termasuk dalam namespace secara eksplisit, jadi jika Anda memiliki dua fungsi generik dengan nama yang sama, Anda harus menjelaskan yang Anda gunakan.

Singkatnya, fungsi yang "berbeda secara konseptual" akan selalu memiliki nama yang berbeda, atau tinggal di ruangnama yang berbeda.


9
2018-03-04 08:29



Fungsi generik harus melakukan "verb" yang sama untuk semua kelas yang diimplementasikan metodenya.

Dalam kasus binatang / pohon "kulit kayu", kata kerja hewan adalah "melakukan tindakan suara" dan dalam kasus pohon, yah, saya kira itu membuat-lingkungan-perisai.

Bahasa Inggris itu terjadi untuk menyebut mereka berdua "kulit kayu" hanyalah sebuah co-insiden linguistik.

Jika Anda memiliki kasus di mana beberapa GF yang berbeda (fungsi umum) benar-benar harus memiliki nama yang sama, menggunakan ruang nama untuk memisahkannya adalah (mungkin) hal yang benar.


3
2018-03-04 11:45



Pesan-lewat OO tidak, secara umum, memecahkan masalah namespacing yang Anda bicarakan. Bahasa OO dengan sistem tipe struktural tidak membedakan antara metode barkdalam sebuah Animal atau a Tree selama mereka memiliki tipe yang sama. Ini hanya karena bahasa OO populer menggunakan sistem tipe nominal (misalnya, Java) yang tampaknya seperti itu.


2
2018-03-04 17:21



Karena get-x () dari XYZ tidak memiliki hubungan konseptual untuk mendapatkan-x () GENE,   mereka diimplementasikan sebagai fungsi generik yang terpisah

Yakin. Tetapi karena argumen mereka sama (hanya meneruskan objek ke metode), maka Anda 'bisa' menerapkannya sebagai metode berbeda pada fungsi generik yang sama.

Satu-satunya kendala saat menambahkan metode ke fungsi generik, adalah bahwa arglist dari metode tersebut sesuai dengan argumen dari fungsi generik.

Secara umum, metode harus memiliki jumlah yang diperlukan dan sama   parameter opsional dan harus mampu menerima argumen apa pun   sesuai dengan setiap & istirahat atau & parameter kunci yang ditentukan oleh generik   fungsi.

Tidak ada kendala bahwa fungsi harus terkait secara konseptual. Sebagian besar waktu mereka (overriding superclass, dll), tetapi mereka pasti tidak perlu.

Meskipun kendala ini (membutuhkan argumentasi yang sama) nampaknya membatasi waktu. Jika Anda melihat Erlang, fungsi memiliki arity, dan Anda dapat mendefinisikan beberapa fungsi dengan nama yang sama yang memiliki arity berbeda (fungsi dengan nama yang sama dan argumen yang berbeda). Dan kemudian semacam pengiriman mengurus panggilan fungsi yang benar. Saya suka ini. Dan di cadel, saya pikir ini akan memetakan untuk memiliki fungsi generik menerima metode yang memiliki berbagai argumen. Mungkin ini adalah sesuatu yang dapat dikonfigurasi dalam MOP?

Meski membaca sedikit lebih banyak sini, tampaknya argumen kata kunci mungkin memungkinkan programmer untuk mencapai fungsi generik mengenkapsulasi metode dengan arity yang benar-benar berbeda, dengan menggunakan kunci yang berbeda dalam metode yang berbeda untuk memvariasikan jumlah argumen mereka:

Suatu metode dapat "menerima" & kunci dan & argumen istirahat didefinisikan dalam generiknya   berfungsi dengan memiliki parameter & istirahat, dengan memiliki & kunci yang sama   parameter, atau dengan menentukan & izinkan-tombol lainnya bersama & kunci. SEBUAH   metode juga dapat menentukan & parameter kunci tidak ditemukan di generik   daftar parameter fungsi - ketika fungsi generik dipanggil, apa saja   & parameter kunci ditentukan oleh fungsi generik atau yang berlaku   metode akan diterima.

Juga perhatikan bahwa jenis pengaburan ini, di mana metode yang berbeda disimpan dalam fungsi generik yang melakukan hal-hal yang berbeda secara konseptual, terjadi di belakang layar dalam 'pohon memiliki kulit kayu', contoh 'anjing menggonggong'. Ketika mendefinisikan kelas pohon, Anda akan mengatur metode pengambil dan penyetel otomatis untuk slot kulit kayu. Ketika mendefinisikan kelas anjing, Anda akan mendefinisikan metode kulit kayu pada jenis anjing yang sebenarnya menggonggong. Dan kedua metode ini disimpan dalam fungsi generik kulit batang.

Karena keduanya tertutup dalam fungsi generik yang sama, Anda akan memanggilnya dengan cara yang persis sama:

(bark tree-obj) -> Returns a noun (the bark of the tree)
(bark dog-obj) -> Produces a verb (the dog barks)

Sebagai kode:

CL-USER> 
(defclass tree ()
  ((bark :accessor bark :initarg :bark :initform 'cracked)))
#<STANDARD-CLASS TREE>
CL-USER> 
(symbol-function 'bark)
#<STANDARD-GENERIC-FUNCTION BARK (1)>
CL-USER> 
(defclass dog ()
  ())
#<STANDARD-CLASS DOG>
CL-USER> 
(defmethod bark ((obj dog))
  'rough)
#<STANDARD-METHOD BARK (DOG) {1005494691}>
CL-USER> 
(symbol-function 'bark)
#<STANDARD-GENERIC-FUNCTION BARK (2)>
CL-USER> 
(bark (make-instance 'tree))
CRACKED
CL-USER> 
(bark (make-instance 'dog))
ROUGH
CL-USER> 

Saya cenderung mendukung semacam 'dualitas sintaks', atau mengaburkan fitur, dll. Dan saya tidak berpikir bahwa semua metode pada fungsi generik harus serupa secara konseptual. Itu hanya IMO pedoman. Jika interaksi linguistik dalam bahasa Inggris terjadi (kulit sebagai kata benda dan kata kerja), itu bagus untuk memiliki bahasa pemrograman yang menangani kasus dengan anggun.


2
2018-03-04 17:41



Anda bekerja dengan beberapa konsep, dan mencampurnya, seperti: ruang nama, fungsi umum global, fungsi umum lokal (metode), pemanggilan metode, pengiriman pesan, dll.

Dalam beberapa keadaan, konsep-konsep itu mungkin tumpang tindih secara sintaktis, sulit diterapkan. Sepertinya saya juga mencampur banyak konsep dalam pikiran Anda.

Bahasa Fungsional, bukan kekuatan saya, saya telah melakukan beberapa pekerjaan dengan LISP.

Namun, beberapa konsep ini, digunakan dalam paradigma lain, seperti Orientasi Prosedural, & Obyek (Kelas). Anda mungkin ingin memeriksa bagaimana konsep ini diimplementasikan, dan, kemudian, kembali ke bahasa pemrograman Anda sendiri.

Sebagai contoh, sesuatu yang saya anggap sangat penting adalah penggunaan namespace ("modules"), sebagai konsep terpisah dari Prosedural Programming, dan menghindari bentrokan identifier, seperti yang Anda sebutkan. Bahasa pemrograman dengan namespace seperti milik Anda, akan menjadi seperti ini:

=== dalam file animal.code ===

define module animals

define class animal
  // methods doesn't use "bark(animal AANIMAL)"
  define method bark()
  ...
  end define method
end define class

define class dog
  // methods doesn't use "bark(dog ADOG)"
  define method bark()
  ...
  end define method
end define class

end define module

=== dalam file myprogram.code ===

define module myprogram

import animals.code
import trees.code

define function main
  a = new-dog()
  a.bark() //Make the dog bark

  …

  t = new-tree()
  b = t.bark() //Retrieve the bark from the tree
end define function main

end define module

Tepuk tangan.


0
2018-04-30 23:16



Ini adalah pertanyaan umum di mana menempatkan tabel pengiriman banyak bahasa pemrograman yang mencoba alamat dengan cara yang nyaman.

Dalam kasus OOP kami memasukkannya ke dalam definisi kelas (kami memiliki tipe + fungsi konkresi dengan cara ini, dibumbui dengan warisan itu memberikan semua kesenangan dari masalah arsitektur).

Dalam kasus FP kami memasukkannya ke dalam fungsi pengiriman (kami memiliki tabel terpusat bersama, ini biasanya tidak terlalu buruk, tetapi tidak sempurna juga).

Saya suka pendekatan berbasis antarmuka, ketika saya dapat membuat tabel virtual secara terpisah dari tipe data apa pun DAN dari definisi fungsi bersama (protokol di Clojure).

Di Java (maaf) akan terlihat seperti ini:

Mari berasumsi ResponseBody adalah sebuah antarmuka.

public static ResponseBody create(MediaType contentType,
     long contentLength, InputStream content) {

    return new ResponseBody() {
      public MediaType contentType() {
        return contentType;
      }

      public long contentLength() {
        return contentLength;
      }

      public BufferedSource source() {
        return streamBuffered(content);
      }
    };
}

Tabel virtual dibuat untuk spesifik ini create fungsi. Ini benar-benar menyelesaikan masalah namespace, Anda juga dapat memiliki pengiriman berbasis-jenis non-terpusat (OOP) jika Anda menghendaki.

Hal ini juga menjadi sepele untuk memiliki implementasi terpisah tanpa mendeklarasikan tipe data baru untuk tujuan pengujian.


0
2018-01-13 23:37