Ưu và nhược điểm của hằng số giao diện [đóng]


105

Các giao diện PHP cho phép định nghĩa các hằng số trong một giao diện, ví dụ:

interface FooBar
{
    const FOO = 1;
    const BAR = 2;
}
echo FooBar::FOO; // 1

Bất kỳ lớp triển khai nào sẽ tự động có sẵn các hằng số này, ví dụ:

class MyFooBar implement FooBar
{
}
echo MyFooBar::FOO; // 1

Bản thân tôi nghĩ rằng bất cứ thứ gì Toàn cầu đều là Ác ma . Nhưng tôi tự hỏi liệu điều tương tự có áp dụng cho Hằng số giao diện hay không. Cho rằng Mã hóa theo giao diện được coi là phương pháp tốt nói chung, việc sử dụng Hằng số giao diện có phải là hằng số duy nhất được chấp nhận để sử dụng bên ngoài ngữ cảnh lớp không?

Mặc dù tôi tò mò muốn nghe ý kiến ​​cá nhân của bạn và liệu bạn có sử dụng hằng số Giao diện hay không, tôi chủ yếu tìm kiếm lý do khách quan trong câu trả lời của bạn. Tôi không muốn đây là một câu hỏi Loại Thăm dò ý kiến. Tôi quan tâm đến ảnh hưởng của việc sử dụng hằng số giao diện đối với Khả năng duy trì. Khớp nối. Hoặc Kiểm thử đơn vị. Nó liên quan như thế nào đến SOLID PHP? Nó có vi phạm bất kỳ nguyên tắc viết mã nào được coi là Thực hành Tốt trong PHP không? Bạn có ý tưởng…

Lưu ý: có một câu hỏi tương tự dành cho Java liệt kê một số lý do khá chính xác khiến chúng là Thực hành kém, nhưng vì Java không phải là PHP, tôi cảm thấy thật hợp lý khi hỏi lại nó trong thẻ PHP.


1
Rất tiếc, trước đây tôi chưa bao giờ thấy cần phải xác định hằng số trong giao diện. Cần biết rằng các lớp triển khai giao diện không thể ghi đè các hằng số, trong khi các lớp chỉ mở rộng lẫn nhau có thể ghi đè các hằng số.
Charles

1
Tôi tin rằng các hằng số không xấu vì chúng có các giá trị có thể dự đoán được ngay cả khi chúng ta quan tâm đến khả năng kiểm tra đơn vị. Các biến toàn cục là xấu vì bất kỳ ai cũng có thể thay đổi nó vì nó là một biến và mọi thứ đều có phạm vi trên đó nhưng các hằng số sẽ không bao giờ thay đổi giá trị của nó, do đó thuật ngữ hằng số.
mdprotacio

Câu trả lời:


135

Tôi nghĩ rằng sự khác biệt giữa tốttốt là đủ .

Mặc dù trong hầu hết các trường hợp, bạn có thể tránh việc sử dụng hằng số bằng cách triển khai các mẫu khác (chiến lược hoặc có thể là hạng cân), nhưng có điều cần nói là không cần đến nửa tá lớp khác để đại diện cho một khái niệm. Tôi nghĩ những gì nó tóm tắt lại là khả năng cần các hằng số khác. Nói cách khác, có cần phải mở rộng ENUM được cung cấp bởi các hằng số trên giao diện hay không. Nếu bạn có thể thấy trước cần phải mở rộng nó, thì hãy chọn một mẫu trang trọng hơn. Nếu không, thì nó có thể đủ (nó sẽ đủ tốt và do đó ít mã hơn để viết và kiểm tra). Đây là một ví dụ về việc sử dụng đủ tốt và không tốt:

Xấu:

interface User {
    const TYPE_ADMINISTRATOR = 1;
    const TYPE_USER          = 2;
    const TYPE_GUEST         = 3;
}

Đủ tốt:

interface HTTPRequest_1_1 {
    const TYPE_CONNECT = 'connect';
    const TYPE_DELETE  = 'delete';
    const TYPE_GET     = 'get';
    const TYPE_HEAD    = 'head';
    const TYPE_OPTIONS = 'options';
    const TYPE_POST    = 'post';
    const TYPE_PUT     = 'put';

    public function getType();
}

Bây giờ, lý do mà tôi chọn những ví dụ đó rất đơn giản. Các Usergiao diện được xác định một enum các loại người dùng. Điều này rất có thể mở rộng theo thời gian và sẽ phù hợp hơn với một mẫu khác. Nhưng đây HTTPRequest_1_1là một trường hợp sử dụng tốt, vì enum được định nghĩa bởi RFC2616 và sẽ không thay đổi trong suốt thời gian tồn tại của lớp.

Nói chung, tôi không thấy vấn đề với hằng số và hằng số lớp là một vấn đề toàn cầu . Tôi xem nó như một vấn đề phụ thuộc. Đó là một sự khác biệt hẹp, nhưng là một sự phân biệt rõ ràng. Tôi thấy các vấn đề toàn cầu như trong các biến toàn cục không được thực thi và như vậy tạo ra một sự phụ thuộc toàn cầu mềm. Nhưng một lớp được mã hóa cứng tạo ra một sự phụ thuộc được thực thi và như vậy tạo ra một sự phụ thuộc toàn cục cứng. Vì vậy, cả hai đều là phụ thuộc. Nhưng tôi cho rằng toàn cầu còn tệ hơn nhiều vì nó không được thực thi ... Đó là lý do tại sao tôi không thích gộp các phụ thuộc lớp với các phụ thuộc toàn cục dưới cùng một biểu ngữ ...

Nếu bạn viết MyClass::FOO, bạn đã được mã hóa các chi tiết triển khai của MyClass. Điều này tạo ra một khớp nối cứng, làm cho mã của bạn kém linh hoạt hơn, và điều này nên tránh. Tuy nhiên, các giao diện tồn tại để cho phép chính xác loại khớp nối này. Do đó MyInterface::FOOkhông giới thiệu bất kỳ khớp nối bê tông nào. Với điều đó đã nói, tôi sẽ không giới thiệu một giao diện chỉ để thêm một hằng số vào nó.

Vì vậy, nếu bạn đang sử dụng giao diện và bạn rất chắc chắn rằng bạn (hoặc bất kỳ ai khác về vấn đề đó) sẽ không cần các giá trị bổ sung, thì tôi thực sự không thấy vấn đề lớn với các hằng số giao diện ... thiết kế sẽ không bao gồm bất kỳ hằng số hoặc điều kiện hoặc số ma thuật hoặc chuỗi ma thuật hoặc bất kỳ thứ gì được mã hóa cứng. Tuy nhiên, điều đó làm tăng thêm thời gian để phát triển, vì bạn phải xem xét việc sử dụng. Quan điểm của tôi là hầu hết thời gian hoàn toàn xứng đáng để dành thêm thời gian để xây dựng một thiết kế vững chắc tuyệt vời. Nhưng có những lúc đủ tốt thực sự có thể chấp nhận được (và cần một nhà phát triển có kinh nghiệm để hiểu được sự khác biệt), và trong những trường hợp đó, nó vẫn ổn.

Một lần nữa, đó chỉ là quan điểm của tôi về nó ...


4
Bạn sẽ đề xuất điều gì làm mẫu khác cho Người dùng trong trường hợp này?
Jacob

@Jacob: Tôi sẽ tóm tắt nó đi. Tùy thuộc vào nhu cầu của bạn, tôi có thể sẽ xây dựng một lớp Access lấy dữ liệu của nó từ một bảng cơ sở dữ liệu. Bằng cách đó, việc thêm một cấp độ mới cũng dễ dàng như chèn một hàng mới. Một tùy chọn khác là xây dựng một tập hợp lớp ENUM (trong đó bạn có một lớp cho mỗi vai trò quyền). Sau đó, bạn có thể mở rộng các lớp khi cần thiết để cung cấp các quyền thích hợp. Nhưng cũng có những phương pháp khác mà sẽ làm việc quá
ircmaxell

3
Câu trả lời rất chắc chắn và rõ ràng! +1
Decent Dabbler

1
lớp có hằng số công khai không nên có bất kỳ phương thức nào. Nó chỉ nên là cấu trúc dữ liệu hoặc đối tượng duy nhất - không phải cả hai.
OZ_

2
@FrederikKrautwald: bạn có thể tránh điều kiện với đa hình (trong hầu hết các trường hợp): Kiểm tra câu trả lời này ra cũng như xem talk Mã sạch này ...
ircmaxell

10

Tôi nghĩ rằng việc xử lý các hằng số, các hằng số được liệt kê đặc biệt, dưới dạng một loại riêng biệt ("lớp") từ giao diện của bạn sẽ tốt hơn:

define(TYPE_CONNECT, 'connect');
define(TYPE_DELETE , 'delete');
define(TYPE_GET    , 'get');
define(TYPE_HEAD   , 'head');
define(TYPE_OPTIONS, 'options');
define(TYPE_POST   , 'post');
define(TYPE_PUT    , 'put');

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

hoặc nếu bạn muốn sử dụng một lớp làm không gian tên:

class TypeHTTP_Enums
{
  const TYPE_CONNECT = 'connect';
  const TYPE_DELETE  = 'delete';
  const TYPE_GET     = 'get';
  const TYPE_HEAD    = 'head';
  const TYPE_OPTIONS = 'options';
  const TYPE_POST    = 'post';
  const TYPE_PUT     = 'put';
}

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

Không phải là bạn chỉ đang sử dụng hằng số, bạn đang sử dụng khái niệm giá trị được liệt kê hoặc kiểu liệt kê, mà một tập hợp các giá trị bị hạn chế, được coi là một kiểu cụ thể, với cách sử dụng cụ thể ("miền"?)

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.