Kết hợp mẫu thành ngữ tương đương trong Java


9

Tôi đang xây dựng một trình giả lập phân tích một số sự kiện từ đó STDINvà "chạy" chúng. Nền tảng của tôi chủ yếu là lập trình chức năng những ngày này, vì vậy có vẻ tự nhiên để làm một cái gì đó như thế này:

data Event = Thing1 String Int | Thing2 Int | Thing3 String String Int
Parse :: String -> [Event]
Simulate :: [Event] -> [Result]

mô phỏng ở đâu

case event
  of Thing1 a b => compute for thing one
   | Thing2 a => compute for thing two

v.v ... Cách thành ngữ để làm điều này trong Java là gì? Googling đã chỉ cho tôi theo hướng các lớp lồng nhau và mô hình khách truy cập, nhưng điều đó có vẻ khá nặng nề trong nỗ lực của tôi. Loại tẩy xóa dường như đang chiến đấu với tôi, khó khăn. Bạn có thể chỉ cho tôi một phác thảo về những gì sẽ trông giống như được thực hiện chính xác?


1
Có lẽ phụ thuộc vào loại đến một mức độ nào đó. Bạn có thể mô tả ngắn gọn về sự kiện và các thành viên int / chuỗi của nó có nghĩa là gì không? Ví dụ, Eventloại có tương đương về mặt khái niệm với việc có một Intvà hai Maybe Stringskhông?
Ixrec

1
Java có phải là ngôn ngữ bạn muốn hoặc bạn phải làm việc với?
Thomas Junk

Khớp mẫu có thể là một tính năng trong tương lai trong Java 1x, được mô tả trong JEP 305 .
tsh

Câu trả lời:


10

Tác giả của 'Lập trình hàm trong Scala' đưa ra một minh họa hay về những điều tốt nhất có thể đạt được trong Java theo cách an toàn:

http://blog.higher-order.com/blog/2009/08/21/structural-potype-matching-in-java/

Về cơ bản, nó sử dụng mã hóa Church của các trường hợp để đảm bảo rằng trình biên dịch sẽ khiếu nại nếu có thiếu.

Các chi tiết không dễ dàng được tóm tắt và thực sự được trình bày rất kỹ trong bài viết đến nỗi không có điểm nào để sao chép chúng ở đây (đó là những siêu liên kết nào cho đúng?).


Cảm ơn, đây ít nhiều là những gì tôi đang tìm kiếm. Khách truy cập cuối cùng đã làm việc hợp lý tốt cho trường hợp này, nhưng tôi có thể sẽ sử dụng ví dụ của Giáo hội trong tương lai.
closeparen

2
Tôi nghĩ điều đó thật thông minh, nhưng tôi không chắc nó là thành ngữ
Brian Agnew

Tương đương thành ngữ là công văn kép, trong đó bạn truyền một đối tượng cho t.matchba phương thức chứ không phải truyền ba hàm. (Bài viết liên kết lẫn lộn mẫu truy cập với văn đôi - khách truy cập là khuôn mẫu cho việc trừu tượng hóa lặp qua mạng, chứ không phải để lựa chọn trên các mẫu)
Pete Kirkham

Công văn đôi là một cách để thực hiện mô hình Khách truy cập. Tôi không biết ý của bạn là gì khi 'trừu tượng hóa việc lặp lại qua mạng' - đó không phải là cụm từ được sử dụng trong định nghĩa của Khách truy cập.
NietzscheanAI

Tôi đang vật lộn với blog / bài viết này bởi vì anh ấy bắt đầu với điều này trong ví dụ 'xấu' của public static int depth(Tree t)anh ấy : nơi anh ấy sử dụng chuỗi nếu một ví dụ khi cách 'đúng' để làm điều này trong Java là xác định giao diện với phương thức: public int depth()và sử dụng đa hình. Có vẻ như một người đàn ông rơm.
JimmyJames

4

Cách thành ngữ để làm điều này trong Java là gì?

Thực sự không có chuyện như vậy, vì Java (ngôn ngữ) về cơ bản là bắt buộc.

Nếu bạn có thể chạy trên JVM, nhưng không bị hạn chế đối với ngôn ngữ Java , bạn có thể điều tra Scala, điều này sẽ đạt được một cái gì đó giống như ở trên bằng cách sử dụng khớp mẫu .

Mặt khác, tôi nghĩ rằng bạn đã giảm việc khớp thủ công các trường hợp khác nhau và các phương thức gọi của mình là phù hợp hoặc có thể xác định các kiểu con của 'Sự kiện' và sử dụng đa hình để gọi các phương thức cụ thể cho từng kiểu con.


Tôi nghĩ đoạn cuối của bạn đập vào đầu đinh. Cách tiếp cận thành ngữ này trong Java là sử dụng đa hình. Có sự kiện là một giao diện với một phương thức thích hợp và Thing1, Thing2 và Thing3 là các triển khai của giao diện đó. Nó phân tách mã theo loại chứ không phải theo chức năng, nhưng về cơ bản đó là điểm của OOP, phải không?
Jules

Java là bắt buộc là không quan trọng. Java có thể (và nên) tích hợp các loại tổng, nhưng thực tế không phải vậy.
vườn

1

Hãy xem https://github.com/johnlcox/motif là thư viện "khớp mẫu" giống như Scala cho Java 8.

Không đẹp như ML / Erlang / Haskell, nhưng vẫn có vẻ khai báo hơn nhiều so với hầu hết.


0

Bạn có thể sử dụng enum và giao diện, ghi đè phương thức mô phỏng, như thế này:

interface Event {
  void simulate()
}

enum MyEvents implements Event {
  THING1 {
    @Override
    void simulate() {
    //...
    }
  },
  THING2 {
    @Override
    void simulate() {
    //...
    }
  },
}

Hãy nói rằng bạn có Event event. Sau đó, bạn có thể sử dụng nó theo một trong hai cách:

event.simulate();

hoặc là

switch(event) {
  case THING1:
    //..
    break;
  case THING2:
    break;
}

Nhưng hàm tạo được JVM gọi tự động, do đó, để lưu trữ các tham số mà bạn sẽ phải thêm các thuộc tính với các bộ truy cập, v.v.

Ngoài ra, bạn có thể mã hóa các sự kiện của mình dưới dạng chuỗi không đổi và sử dụng switchcấu trúc, trong trường hợp đó bạn sẽ làm

string event = args[0];
switch(event){
  case THING1:
    int a = args[1];
    //...
    break;
  case THING2:
    int a = args[1];
    int b = args[2];
    break;
}

v.v. Nhưng vâng, không có gì bản địa bắt chước mô hình khớp trực tiếp :(


Tôi không chắc tại sao bạn sử dụng một enum ở đây chứ không phải các lớp học - lợi ích của enum là gì?
Jules

Bởi vì sau đó bạn cũng có thể sử dụng nó trong một câu lệnh chuyển đổi, điều này làm cho nó hơi giống với khớp mẫu
jasiek.miko

thêm rằng trong bây giờ.
jasiek.miko

0

Mô hình khách truy cập hoặc tương đương mã hóa nhà thờ của nó là cách để đi. Nó khá dài dòng trong Java, nhưng hy vọng các công cụ như Derive4J (bộ xử lý chú thích tôi duy trì) hoặc Adt4J có thể tạo ra bản tóm tắt . Sử dụng một công cụ như vậy, ví dụ của bạn trở thành:

import java.util.function.Function;
import org.derive4j.Data;

@Data
public abstract class Event {

  interface Cases<X> {
    X Thing1(String s, int i);
    X Thing2(int i);
    X Thing3(String s, String s2, int i);
  }

  abstract <X> X match(Cases<X> cases);

  static Function<Event, Result> Simulate =
      Events.cases().
          Thing1( (s, i    ) -> computeForThingOne(s, i)       ).
          Thing2( (i       ) -> computeForThingTwo(i)          ).
          Thing3( (s, s2, i) -> computeForThingThree(s, s2, i) );

}

Derive4J tạo lớp Sự kiện cung cấp cú pháp khớp mẫu trôi chảy (với kiểm tra toàn diện rằng tất cả các trường hợp được xử lý).


Bạn có thể làm rõ mối liên kết của bạn với dự án trong bài đăng của bạn (xem, stackoverflow.com/help/promotion ).
Benni
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.