2010-01-31 25 views
7

Tôi có một câu hỏi không còn là một câu hỏi thiết kế nữa. Tôi có một lớp định nghĩa một loạt các hàm. Tuy nhiên, tôi muốn rằng hành vi của một số chức năng có thể thay đổi trong thời gian chạy - hoặc ít nhất là làm việc như một giao diện plugin trong thời gian thiết kế. ví dụ:Các lớp PHP đa hình/có thể cắm được

class MyClass { 
    public function doSomething(); 
} 

$obj = new MyClass(); 
// PSEUDO CODE 
$obj->doSomething = doSomethingElse; 
$obj->doSomething(); // does something else 

Tôi đã có nhiều ý tưởng khác nhau về cách triển khai một cái gì đó như thế này trong mã "thực". Tuy nhiên, tôi không hoàn toàn chắc chắn, đó là con đường đúng đắn để đi. Lần đầu tiên tôi nghĩ rằng tôi có thể sử dụng một giao diện cho mục đích này.

interface IDoSomethingInterface { 
    public function doSomething(); 
} 

class DoSomethingClass implements IDoSomethingInterface 
{ 
    public function doSomething() 
    { 
    // I do something! 
    } 
} 

class DoSomethingElseClass implements IDoSomethingInterface 
{ 
    public function doSomething() 
    { 
    // I actually do something else! 
    } 
} 

class MyClass { 
    public doSomething(IDoSomething $doSomethingProvider) 
    { 
    $doSomethingProvider->doSomething(); 
    } 
} 

$obj = new MyClass(); 
$doSomethingProvider = new DoSomethingClass(); 
$doSomethingElseProvider = new DoSomethingElseClass(); 

$obj->doSomething($doSomethingProvider); // I do something! 
$obj->doSomething($doSomethingElseProvider); // I do something else! 

Cách tiếp cận này có thể được mở rộng để không có nhà cung cấp doSomething được truyền làm tham số, nhưng để đặt thành đối tượng hoặc thậm chí là thành viên của lớp. Tuy nhiên, tôi không thích rằng tôi phải tạo một thể hiện của lớp n mà thậm chí không chứa một biến thành viên duy nhất và phương thức duy nhất có thể dễ dàng là một hàm lớp tĩnh. Không cần một đối tượng tại thời điểm đó. Tôi sau đó sẽ cố gắng sử dụng các biến chức năng - nhưng tôi sẽ rơi ra khỏi OOP sau đó, mà tôi không thích hoặc. Câu hỏi của tôi là: đó là cách tốt nhất để thực hiện một hệ thống như tôi đã mô tả? Bạn sẽ thử hoặc sử dụng phương pháp nào? Có điều gì rõ ràng tôi có thể không nghĩ đến? Hay tôi chỉ nên đi với cách tiếp cận giao diện và cảm giác tồi tệ của tôi về việc tạo ra những vật thể 'thân mật' chỉ là một thứ quý giá ?! Tôi tò mò về câu trả lời của bạn!

Edit:

Bởi vì tôi thực sự quan tâm đến việc làm rõ nếu điều này thực sự là (hoặc nên là) một nhà nước hoặc một mẫu chiến lược, tôi sẽ đi vào một số chi tiết thêm về việc thực hiện. Tôi có một lớp cơ sở của các bộ sưu tập mà từ đó tôi lấy được các triển khai cụ thể khác nhau. Tôi muốn để có thể chọn một yếu tố duy nhất từ ​​bất kỳ thực hiện cụ thể - tuy nhiên, tôi muốn có thể tự động thay đổi như thế nào yếu tố này được chọn từ bộ sưu tập, ví dụ:

class MyCollection implements Countable, ArrayAcces, Iterator 
{ 
    // Collection Implementation 
    public function select(ISelectionStrategy $strategy) 
    { 
    return $strategy->select($this); 
    } 
} 

interface ISelectionStrategy 
{ 
    public function select(MyCollection $collection); 
} 

class AlphaSelectionStrategy implements ISelectionStrategy 
{ 
    public function select(MyCollection $collection); 
    { 
    reset($collection); 
    if (current($collection)) 
     return current($collection); 
    else 
     return null; 
    } 
} 

class OmegaSelectionStrategy implements ISelectionStrategy 
{ 
    public function select(MyCollection $collection) 
    { 
    end($collection); 
    if (current($collection)) 
     return current($collection) 
    else 
     return null; 
    } 
} 

class RandomSelectionStrategy implements ISelectionStrategy 
{ 
    public function select(MyCollection $collection) 
    { 
    if (!count($collection)) 
     return null; 
    $rand = rand(0, count($collection)-1); 
    reset($collection); 
    while($rand-- > 0) 
    { 
     next($collection); 
    } 
    return current($collection); 
    } 
} 

$collection = new MyCollection(); 
$randomStrategy = new RandomSelectionStrategy(); 
$alphaStrategy = new AlphaSelectionStrategy(); 
$omegaStrategy = new OmegaSelectionStrategy(); 

$collection->select($alphaStrategy); // return first element, or null if none 
$collection->select($omegaStrategy); // return last element, or null if none 
$collection->select($randomStrategy); // return random element, or null if none 

này là cơ bản những gì tôi muốn đạt được . Đây có phải là thực hiện mô hình chiến lược hay mô hình trạng thái hơn nữa - mặc dù tôi đã sử dụng chiến lược hạn vì nó vẫn phù hợp hơn trong trường hợp này. Theo như tôi hiểu chiến lược và mô hình nhà nước một cách cơ bản giống nhau, ngoại trừ ý định của họ là khác nhau. Liên kết được cung cấp bởi Gordon nói rằng ý định của một mẫu trạng thái là "Cho phép một đối tượng thay đổi hành vi của nó khi trạng thái nội tại của nó thay đổi" - nhưng đây không phải là trường hợp ở đây. Những gì tôi muốn là để có thể nói cho lớp MyCollection của tôi "sử dụng thuật toán này hoặc để cho tôi một phần tử" - không "cho tôi một yếu tố bằng cách sử dụng một thuật toán mà bạn xác định thông qua trạng thái của riêng bạn". Hy vọng ai đó có thể làm rõ điều này!

Trân trọng, Daniel

+1

+1, nụ cười đó sẽ là kết thúc của tôi. xP –

+0

Vâng, bạn đã tự trả lời câu hỏi của mình. Bạn không muốn quản lý các tiểu bang. Bạn muốn trao đổi những hành vi đơn lẻ, vì vậy Chiến lược là thích hợp. Trên một sidenote, vì bạn có vẻ là người Đức, tôi có thể giới thiệu cuốn sách phpdesignpatterns.de – Gordon

Trả lời

4

cách tiếp cận của bạn là đúng. Nó là một Strategy Pattern (UML diagram):

Kiểm tra câu trả lời của tôi cho câu hỏi này (bỏ qua đến nơi nó nói Vì bạn muốn tự động thay đổi hành vi):

Một thay thế cho UseCase cụ thể của bạn sẽ là tập hợp các Chiến lược lựa chọn vào một lớp Dịch vụ duy nhất, thay vì chỉ định chúng cho lớp Bộ sưu tập của bạn. Sau đó, thay vì chuyển các chiến lược cho bộ sưu tập, hãy chuyển bộ sưu tập đến Lớp dịch vụ, ví dụ:

class CollectionService implements ICollectionSelectionService 
{ 
    public static function select(MyCollection $collection, $strategy) { 
     if(class_exists($strategy)) { 
      $strategy = new $strategy; 
      return $strategy->select($collection); 
     } else { 
      throw new InvalidArgumentException("Strategy does not exist"); 
     }  
    } 
} 
$element = CollectionService::select($myCollection, 'Alpha'); 

Tôi sẽ tùy thuộc vào bạn có nên sử dụng phương pháp này với phương pháp tĩnh hay không. Để ngăn chặn nhiều phiên bản của các chiến lược Lựa chọn, bạn có thể lưu trữ các đối tượng Lựa chọn bên trong Dịch vụ để sử dụng lại.

Đối với mẫu hành vi khác kiểm tra

+0

Cảm ơn rất nhiều! Bây giờ tôi sẽ chỉ cần nhấn mạnh rằng "Không .. Cần .. Object .. Đây .. Urgs .." - cảm giác;) –

+0

Tính đến 5.3, bạn có thể sử dụng các bao đóng cho phương pháp này, nhưng sau đó bạn không thể gõ gợi ý hoặc chương trình chống lại một giao diện nữa. – Gordon

+0

Chiến lược được sử dụng để cung cấp thuật toán tối ưu hóa - ví dụ như Tìm kiếm nhị phân khi giao dịch với mảng được sắp xếp thay vì Tìm kiếm tuyến tính cho mảng chưa được sắp xếp. Ngoài ra, lựa chọn chiến lược thường được thực hiện bằng cách sử dụng các phương thức quá tải, không được hỗ trợ trong PHP (__call cũng không thực hiện được công việc tuyệt vời ở đây). Tôi nghĩ rằng mô hình nhà nước là phù hợp hơn trong trường hợp này - nó áp dụng việc thực hiện đúng dựa trên trạng thái cấu hình bên ngoài. –

3

Các giải pháp bạn nêu là nhiều hơn hoặc ít hơn đúng. Bạn có thể không biết điều này, nhưng điều này là trong thực tế "State" Design Pattern. Trạng thái của hệ thống được đại diện bởi đối tượng. Nếu bạn cần thay đổi trạng thái, bạn chỉ cần thay thế đối tượng bằng một trạng thái khác.

alt text http://dofactory.com/Patterns/Diagrams/state.gif

Tôi muốn giới thiệu ở lại với những gì bạn có, vì nó đã được chứng minh bởi GOF là giải pháp khả thi.

+0

Cũng xin cảm ơn, tôi tin rằng "Mô hình chiến lược" thực sự là mẫu và thuật ngữ chính xác. –

+0

Hey Dan, tại thời điểm này chúng tôi có lẽ nhận được quá pedantic, nhưng tôi khá tự tin rằng nhà nước là chính xác những gì bạn đang tìm kiếm. Toàn bộ điểm của trạng thái là đối tượng State (implementor) có thể được thiết lập trên đối tượng master từ bên ngoài nó, trong khi đó Strategy trong quyết định thực thi nào được thực hiện trong đối tượng master mà không có cách nào thay đổi nó từ bên ngoài. Dù sao, những gì bạn có tại thời điểm này làm cho cảm giác hoàn hảo. –

+0

Dù bằng cách nào, điều này vẫn đáng giá. Đối với tôi, Gang of bốn mẫu không phải là nhiệm vụ nghiêm khắc do-it-this-way, nhưng nhắc nhở rằng đề xuất nguyên tắc thiết kế tốt để được áp dụng linh hoạt. Có sự tương đồng giữa trạng thái và các mẫu chiến lược, vì cả hai đều có triển khai có thể chuyển đổi làm mục tiêu chính. Chính xác về mô hình nào có giá trị, nhưng những ý tưởng cơ bản chính là tiền thưởng thực sự. – Steve314

Các vấn đề liên quan