Phương thức Enum của Java - trả về hướng ngược lại enum


113

Tôi muốn khai báo một Hướng enum, có một phương thức trả về hướng ngược lại (điều sau không đúng về mặt cú pháp, tức là không thể khởi tạo enum, nhưng nó minh họa quan điểm của tôi). Điều này có khả thi trong Java không?

Đây là mã:

public enum Direction {

     NORTH(1),
     SOUTH(-1),
     EAST(-2),
     WEST(2);

     Direction(int code){
          this.code=code;
     }
     protected int code;
     public int getCode() {
           return this.code;
     }
     static Direction getOppositeDirection(Direction d){
           return new Direction(d.getCode() * -1);
     }
}

Chỉ cần sử dụng một công tắc. Bạn chỉ có 4 trường hợp.
Sotirios Delimanolis

12
Nhân tiện, d.getCode() * -1==-d.getCode()
tckmn

Chương 6 (ít nhất là trong 2E) của Bloch's hiệu quả Java có thể được quan tâm và rất được khuyến khích.
jedwards

ntu.edu.sg/home/ehchua/programming/java/javaenum.html , phần 2.1 đã giải thích khái niệm này một cách gọn gàng
vikramvi

Câu trả lời:


206

Đối với những người bị thu hút ở đây bằng tiêu đề: vâng, bạn có thể xác định các phương thức của riêng mình trong enum của bạn. Nếu bạn đang tự hỏi làm thế nào để gọi phương thức không tĩnh như vậy, bạn thực hiện theo cách tương tự như với bất kỳ phương thức không tĩnh nào khác - bạn gọi nó trên trường hợp của kiểu định nghĩa hoặc kế thừa phương thức đó. Trong trường hợp enums các trường hợp như vậy chỉ đơn giản là ENUM_CONSTANTs.

Vì vậy, tất cả những gì bạn cần là EnumType.ENUM_CONSTANT.methodName(arguments).


Bây giờ chúng ta hãy quay lại vấn đề từ câu hỏi. Một trong những giải pháp có thể là

public enum Direction {

    NORTH, SOUTH, EAST, WEST;

    private Direction opposite;

    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        EAST.opposite = WEST;
        WEST.opposite = EAST;
    }

    public Direction getOppositeDirection() {
        return opposite;
    }

}

Hiện nay Direction.NORTH.getOppositeDirection() sẽ trở lại Direction.SOUTH.


Đây là cách "hacky" hơn một chút để minh họa nhận xét @jedwards nhưng nó không linh hoạt như cách tiếp cận đầu tiên vì việc thêm nhiều trường hoặc thay đổi thứ tự của chúng sẽ phá vỡ mã của chúng ta.

public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    // cached values to avoid recreating such array each time method is called
    private static final Direction[] VALUES = values();

    public Direction getOppositeDirection() {
        return VALUES[(ordinal() + 2) % 4]; 
    }
}

3
Tôi đã chuẩn bị .values()[ordinal()]tấn công một vụ hack nhưng cách tiếp cận này mạnh mẽ hơn nhiều
jedwards

bạn sử dụng nó như thế nào? và kỹ thuật này được gọi là gì?
Thufir

1
@Thufir " bạn sử dụng nó như thế nào " nếu bạn đang hỏi về phương thức, thì cũng giống như bất kỳ phương thức nào khác - bạn gọi nó đối với trường hợp của lớp có phương thức này. Trường hợp của Directionlớp enum là NORTH, EAST, SOUTH, WESTvì vậy bạn chỉ có thể sử dụng NORTH.getOppositeDirection()và nó sẽ trở lại SOUTH. " Kỹ thuật này được gọi là gì? " nếu bạn đang hỏi static{...}thì đó là khối khởi tạo tĩnh , nó là mã được gọi khi lớp được tải lần đầu tiên (nó là một phần của cùng một quy trình khởi tạo các trường tĩnh).
Pshemo

@Pshemo, tôi tự hỏi phiên bản Spring của đoạn mã trên sẽ như thế nào, nếu các giá trị đang được đặt trong khối tĩnh cần được đưa vào từ tệp thuộc tính nói.
Vikas Prasad

162

Đối với một enum nhỏ như thế này, tôi thấy giải pháp dễ đọc nhất là:

public enum Direction {

    NORTH {
        @Override
        public Direction getOppositeDirection() {
            return SOUTH;
        }
    }, 
    SOUTH {
        @Override
        public Direction getOppositeDirection() {
            return NORTH;
        }
    },
    EAST {
        @Override
        public Direction getOppositeDirection() {
            return WEST;
        }
    },
    WEST {
        @Override
        public Direction getOppositeDirection() {
            return EAST;
        }
    };


    public abstract Direction getOppositeDirection();

}

8
Ý tưởng tuyệt vời! Điều này cũng tốt khi bạn thường muốn mỗi giá trị enum có một hành vi cụ thể.
OferBr

28

Những công việc này:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction oppose() {
        switch(this) {
            case NORTH: return SOUTH;
            case SOUTH: return NORTH;
            case EAST:  return WEST;
            case WEST:  return EAST;
        }
        throw new RuntimeException("Case not implemented");
    }
}

8
Thay vì trả về null, một mệnh đề mặc định ném một RuntimeException phù hợp có thể tốt hơn để chỉ ra rằng có một lỗi lập trình viên trong việc không xác định một hướng ngược lại cho một hướng mới được thêm vào.
Timothy055,

1
Điều này yêu cầu người gọi xử lý null. Nó cũng yêu cầu người bảo trì đảm bảo rằng họ thêm một trường hợp mỗi khi một loại Hướng mới được thêm vào. Xem câu trả lời của Amir Afghanistan về việc sử dụng một phương thức trừu tượng có thể bị ghi đè bởi mỗi giá trị enum, theo cách đó bạn không bao giờ có nguy cơ bỏ lỡ một giá trị và bạn không phải lo lắng về việc xử lý null.
Michael Peterson

14

Tạo một phương thức trừu tượng và có mỗi giá trị liệt kê của bạn ghi đè lên nó. Vì bạn biết điều ngược lại trong khi tạo nó, nên không cần phải tạo hoặc tạo động.

Tuy nhiên, nó không được đọc tốt; có lẽ a switchsẽ dễ quản lý hơn?

public enum Direction {
    NORTH(1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.SOUTH;
        }
    },
    SOUTH(-1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.NORTH;
        }
    },
    EAST(-2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.WEST;
        }
    },
    WEST(2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.EAST;
        }
    };

    Direction(int code){
        this.code=code;
    }
    protected int code;

    public int getCode() {
        return this.code;
    }

    public abstract Direction getOppositeDirection();
}

4

Có, chúng tôi làm điều đó mọi lúc. Bạn trả về một cá thể tĩnh thay vì một Đối tượng mới

 static Direction getOppositeDirection(Direction d){
       Direction result = null;
       if (d != null){
           int newCode = -d.getCode();
           for (Direction direction : Direction.values()){
               if (d.getCode() == newCode){
                   result = direction;
               }
           }
       }
       return result;
 }

0
public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    public Direction getOppositeDirection(){
        return Direction.values()[(this.ordinal() + 2) % 4];
    }
}

Enum có một phương thức giá trị tĩnh trả về một mảng chứa tất cả các giá trị của enum theo thứ tự chúng được khai báo. nguồn

vì NORTH được 1, EAST được 2, SOUTH được 3, WEST được 4; bạn có thể tạo một phương trình đơn giản để lấy phương trình ngược lại:

(giá trị + 2)% 4


2
tại sao đây là câu trả lời? Làm thế nào bạn mong đợi điều này sẽ giúp độc giả tương lai, hoặc bất kỳ ai về vấn đề đó, tìm hiểu mà không cần bất kỳ lời giải thích nào?
GrumpyCrouton

Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách thức và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, chứ không chỉ người hỏi bây giờ! Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định nào được áp dụng. Cũng không có hại gì khi đề cập đến lý do tại sao câu trả lời này thích hợp hơn những câu khác.
ItamarG3

có khó để đọc mã mà không có bình luận? hay bạn cần một javadoc dành riêng cho 7 dòng mã?
Pregunton

1
Dung dịch này giòn vì nó phụ thuộc vào thứ tự của các giá trị enum. Nếu bạn thay đổi thứ tự thành bảng chữ cái, phương trình thông minh của bạn sẽ không cung cấp điều ngược lại chính xác nữa.
Josh J
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.