Cara untuk mengembalikan beberapa nilai pengembalian dari suatu metode: letakkan metode di dalam kelas yang mewakili nilai balik. Apakah ini desain yang bagus?


15

Saya perlu mengembalikan 2 nilai dari suatu metode. Pendekatan saya adalah sebagai berikut:

  1. buat kelas dalam dengan 2 bidang yang akan digunakan untuk menjaga 2 nilai tersebut
  2. letakkan metode di dalam kelas itu
  3. instantiate kelas dan panggil metode.

Satu-satunya hal yang akan diubah dalam metode adalah bahwa pada akhirnya itu akan menetapkan 2 nilai tersebut ke bidang instance. Lalu saya bisa mengatasi nilai-nilai itu dengan merujuk ke bidang objek itu.

Apakah ini desain yang bagus dan mengapa?


Pilihan lain (mungkin yang buruk): lihat BitInteger[] java.math.BigInteger.divideAndRemainder(BitInteger val). Ini mengembalikan 2 bilangan bulat sebagai nilai pengembaliannya dalam array.
earlNameless

Jenis apa dua nilai yang ingin Anda kembalikan?
Tulains Córdova

Jawaban:


15

Saya akan berdebat ini di sepanjang baris berikut:

  • Mengapa metode Anda mengembalikan beberapa nilai? Kohesi macam apa yang sedang kita bicarakan - apakah nilai-nilai itu benar-benar menjadi bidang pada satu kelas, atau apakah mereka hanya secara kebetulan dikembalikan dengan metode yang sama, tetapi sebaliknya tidak terkait? Jika ini yang terakhir, Anda mungkin ingin mempertimbangkan untuk membagi metode menjadi dua metode. Sunting: gunakan penilaian Anda di sini; kadang kohesi "kebetulan" bisa menjadi pilihan terbaik. Pilihan lain adalah dengan menggunakan pasangan atau tuple konstruk, meskipun dalam OOP, ini biasanya tidak terlihat di API publik (beberapa pengecualian penting sebagai koleksi standar, dll)
  • Jika nilai-nilai memang layak untuk membentuk kelas, saya mungkin akan menyarankan agar tidak menggunakan kelas batin. Kelas dalam biasanya digunakan sebagai detail implementasi internal, yang disembunyikan dari luar. Apakah ada alasan mengapa hasil ini tidak boleh menjadi kelas "penuh," sendiri?
  • Selain menyimpan data, operasi apa yang berlaku untuk kelas baru ini? Dalam desain berorientasi objek, Anda ingin memiliki perilaku terkait dekat dengan data yang relevan (yang tampaknya juga menjadi niat Anda). Haruskah metode yang Anda maksud tidak tinggal di kelas ini?

Untuk meringkas, saya akan melihat apakah saya bisa mengubah "objek data" ini menjadi kelas yang lengkap dengan data dan perilaku. Sebagai komentar tambahan, Anda mungkin ingin membuat kelas tidak dapat diubah, karena statusnya diatur sekali. Menjadikannya tidak berubah akan membantu mencegahnya diatur secara tidak benar, atau dimodifikasi kemudian (katakanlah, seseorang mengatur salah satu bidang menjadi nol dan meneruskannya).

Sunting: Seperti yang ditunjukkan oleh Patkos Csaba, prinsip yang diterapkan di sini adalah Prinsip Tanggung Jawab Tunggal ( SRP ) - kelas yang Anda coba buat harus benar-benar memiliki satu tanggung jawab (didefinisikan sebagai alasan untuk berubah ). Pedoman desain ini akan membantu Anda mengetahui apakah dua bidang Anda termasuk dalam satu kelas, atau tidak. Untuk tetap menggunakan contoh Wikipedia, kelas Anda dapat dilihat sebagai jenis laporan, dalam hal ini sesuai dengan SRP, tetapi sulit untuk berkomentar tanpa informasi lebih lanjut.


Sementara saya setuju dengan ide umum dari jawaban ini, ada beberapa kasus yang sah ketika dua bagian data yang terkait erat dihitung bersama-sama, tetapi tidak ada gunanya untuk mengikatnya bersama-sama jika tidak di tempat lain dalam program ini. Dalam kasus seperti itu mungkin cukup bersih untuk mengembalikan sesuatu seperti Pair<OneClass, AnotherClass>. Beberapa orang akan tidak setuju . Dalam setiap kasus, Pairharus merupakan detail implementasi dan tidak pernah muncul dalam metode API publik.
9000

@ 9000 Saya setuju; Sebenarnya saya maksudkan kata pertimbangkan untuk dipahami secara harfiah dalam kasus ini, yaitu memecah metode mungkin tidak selalu menjadi solusi terbaik, itu hanya indikasi kasar ke arah itu. Saya akan mengeditnya.
Daniel B

1
Jawaban yang bagus. Satu-satunya hal yang akan saya tambahkan adalah referensi ke Prinsip Tanggung Jawab Tunggal (SRP) ( en.wikipedia.org/wiki/Single_responsibility_principle ). Jika dicentang, sangat mungkin bahwa metode dalam diskusi hanyalah pelanggaran sederhana terhadap SRP dan pemecahan adalah solusi sederhana. Dalam pengalaman saya, setiap kali suatu metode ingin mengembalikan 2 atau lebih nilai, dalam 90% kasus ada 2 metode di sana atau kelas lain harus diekstraksi.
Patkos Csaba

@PatkosCsaba terima kasih, buat edit untuk memasukkannya. Saya biasanya tetap menjelaskan hal-hal dalam hal kopling dan kohesi, tapi saya kira prinsip-prinsip SOLID dilihat sebagai aturan dasar untuk hidup hari ini.
Daniel B

@AnielB: Saya melihat SOLID sebagai level yang lebih tinggi dan mungkin lebih mudah untuk memahami konsep. Kopling dan kohesi masih merupakan dasar, tetapi mereka lebih rendah tingkatnya. SOLID memanfaatkan kopling dan kohesi untuk menjelaskan prinsip-prinsipnya dan menyajikannya pada tingkat yang lebih umum.
Patkos Csaba

10

Ada konsep Tuple yang ditampilkan dalam bahasa lain, seperti Python.

Seseorang dapat mengembalikan instance kelas generik ini yang mudah digunakan kembali:

public class TypedTuple<L, R> implements Serializable {
private static final long serialVersionUID = 1L;

  protected L left;
  protected R right;

  protected TypedTuple() {
    // Default constructor for serialization
  }

  public TypedTuple(L inLeft, R inRight) {
    left = inLeft;
    right = inRight;
  }

  public L getLeft() {
    return left;
  }

  public R getRight() {
    return right;
  }
}

2
Terkadang lebih baik memiliki metode statis generik create(), untuk menghindari keharusan menentukan parameter tipe dalam konstruktor. Juga, saya akan memberi nama kelas ini Pairdaripada Tuple, mengingat itu hanya dapat mewakili 2-tuple nilai.
augurar

5

Tampaknya kelas ini mengambil tanggung jawab dari kelas lain, dan ini membuat saya berpikir bahwa desain ini tidak bagus.

Untuk metode yang mengembalikan nilai multible, saya lebih suka

  • mengembalikan penampung generik (misalnya Daftar atau Peta) yang berisi nilai kembali

atau

  • buat Kelas untuk nilai kembali, yang berisi hanya bidang yang diperlukan + getter + konstruktor dengan semua bidang

Contoh untuk opsi kedua:

public Class FooBarRetval {
   private String foo;
   private int bar;

   public FooBarRetval (String foo, int bar) {
      this.foo = foo;
      this.bar = bar;
   }

   public String getFoo() {
      return foo;
   }

   public int getBar() {
      return bar;
   }
}

Mempublikasikan bidang menambahkan opsi untuk mengubah nilai secara terpisah, meskipun jelas nilai memiliki hubungan (jika tidak, nilai tersebut tidak harus dikembalikan dengan metode yang sama). Saya akan sangat mencegah pola ini dalam situasi khusus ini. Tapi intinya adalah, pembahasan atribut publik vs atribut tidak ada hubungannya dengan pertanyaan OPs dan saya tidak melihat alasan untuk kalimat terakhir dalam jawaban yang baik.
scarfridge

Yang pertama harus disukai.
Juanin

scarfridge: Poin diambil, kalimat terakhir dihapus.
user281377

2
Cukup gunakan bidang final publik, tidak ada alasan untuk membuang waktu dengan pengakses.
augurar


0

Jawaban singkat: Anda dapat mengembalikan array atau Daftar dengan dua nilai.

Saya pribadi akan menulis dua metode yang berbeda, seperti

int x = obj.getX();
int y = obj.getY();
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.