ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 示例 策略模式可以通过允许嵌套对象完成实际工作的方法以及允许将该对象替换为不同对象的设置器来识别。 ## 概念示例 <details> <summary>main.php</summary> ``` <?php class Context { /** * @var Strategy */ private $strategy; /** * @param Strategy $strategy */ public function __construct(Strategy $strategy) { $this->strategy = $strategy; } /** * @param Strategy $strategy */ public function setStrategy(Strategy $strategy) { $this->strategy = $strategy; } public function doSomeBusinessLogic(): void { // ... $result = $this->strategy->doAlgorithm(["a", "b", "c", "d", "e"]); echo implode(",", $result) . "\n"; // ... } } interface Strategy { public function doAlgorithm(array $data): array; } class ConcreteStrategyA implements Strategy { public function doAlgorithm(array $data): array { sort($data); return $data; } } class ConcreteStrategyB implements Strategy { public function doAlgorithm(array $data): array { rsort($data); return $data; } } $context = new Context(new ConcreteStrategyA()); $context->doSomeBusinessLogic(); echo "\n"; $context->setStrategy(new ConcreteStrategyB()); $context->doSomeBusinessLogic(); ``` </details> <br /> 输出 ``` a,b,c,d,e e,d,c,b,a ``` ## 支付方式 <details> <summary>main.php</summary> ``` <?php class OrderController{ /** * Handle POST requests. * @param $url * @param $data * @throws Exception */ public function post(string $url, array $data){ echo "Controller: POST request to $url with ".json_encode($data)."\n"; $path = parse_url($url, PHP_URL_PATH); if(preg_match('#^/orders?$#', $path, $matches)){ $this->postNewOrder($data); }else{ echo "Controller: 404 page\n"; } } /** * Handle GET requests. * @param $url * @throws Exception */ public function get(string $url): void{ echo "Controller: GET request to $url\n"; $path = parse_url($url, PHP_URL_PATH); $query = parse_url($url, PHP_URL_QUERY); parse_str($query, $data); if(preg_match('#^/orders?$#', $path, $matches)){ $this->getAllOrders(); }elseif(preg_match('#^/order/([0-9]+?)/payment/([a-z]+?)(/return)?$#', $path, $matches)){ $order = Order::get($matches[1]); // The payment method (strategy) is selected according to the value // passed along with the request. $paymentMethod = PaymentFactory::getPaymentMethod($matches[2]); if(!isset($matches[3])){ $this->getPayment($paymentMethod, $order, $data); }else{ $this->getPaymentReturn($paymentMethod, $order, $data); } }else{ echo "Controller: 404 page\n"; } } /** * POST /order {data} */ public function postNewOrder(array $data): void{ $order = new Order($data); echo "Controller: Created the order #{$order->id}.\n"; } /** * GET /orders */ public function getAllOrders(): void{ echo "Controller: Here's all orders:\n"; foreach(Order::get() as $order){ echo json_encode($order, JSON_PRETTY_PRINT)."\n"; } } /** * GET /order/123/payment/XX */ public function getPayment(PaymentMethod $method, Order $order, array $data): void{ // The actual work is delegated to the payment method object. $form = $method->getPaymentForm($order); echo "Controller: here's the payment form:\n"; echo $form."\n"; } /** * GET /order/123/payment/XXX/return?key=AJHKSJHJ3423&success=true */ public function getPaymentReturn(PaymentMethod $method, Order $order, array $data): void{ try{ // Another type of work delegated to the payment method. if($method->validateReturn($order, $data)){ echo "Controller: Thanks for your order!\n"; $order->complete(); } }catch(\Exception $e){ echo "Controller: got an exception (".$e->getMessage().")\n"; } } } /** * 一个订单类的简化表示 */ class Order{ /** * 为了简单起见,我们将所有创建的订单存储在这里... * @var array */ private static $orders = []; /** * ...and access them from here. * @param int $orderId * @return mixed */ public static function get(int $orderId = null){ if($orderId === null){ return static::$orders; }else{ return static::$orders[$orderId]; } } /** * The Order constructor assigns the values of the order's fields. To keep * things simple, there is no validation whatsoever. * @param array $attributes */ public function __construct(array $attributes){ $this->id = count(static::$orders); $this->status = "new"; foreach($attributes as $key => $value){ $this->{$key} = $value; } static::$orders[$this->id] = $this; } /** * The method to call when an order gets paid. */ public function complete(): void{ $this->status = "completed"; echo "Order: #{$this->id} is now {$this->status}."; } } class PaymentFactory{ /** * Get a payment method by its ID. * @param $id * @return PaymentMethod * @throws \Exception */ public static function getPaymentMethod(string $id): PaymentMethod{ switch($id){ case "cc": return new CreditCardPayment(); case "paypal": return new PayPalPayment(); default: throw new \Exception("Unknown Payment Method"); } } } interface PaymentMethod{ public function getPaymentForm(Order $order): string; public function validateReturn(Order $order, array $data): bool; } class CreditCardPayment implements PaymentMethod{ static private $store_secret_key = "swordfish"; public function getPaymentForm(Order $order): string{ $returnURL = "https://our-website.com/"."order/{$order->id}/payment/cc/return"; return <<<FORM <form action="https://my-credit-card-processor.com/charge" method="POST"> <input type="hidden" id="email" value="{$order->email}"> <input type="hidden" id="total" value="{$order->total}"> <input type="hidden" id="returnURL" value="$returnURL"> <input type="text" id="cardholder-name"> <input type="text" id="credit-card"> <input type="text" id="expiration-date"> <input type="text" id="ccv-number"> <input type="submit" value="Pay"> </form> FORM; } public function validateReturn(Order $order, array $data): bool{ echo "CreditCardPayment: ...validating... "; if($data['key'] != md5($order->id.static::$store_secret_key)){ throw new \Exception("Payment key is wrong."); } if(!isset($data['success']) || !$data['success'] || $data['success'] == 'false'){ throw new \Exception("Payment failed."); } // ... if(floatval($data['total']) < $order->total){ throw new \Exception("Payment amount is wrong."); } echo "Done!\n"; return true; } } /** * This Concrete Strategy provides a payment form and validates returns for * PayPal payments. */ class PayPalPayment implements PaymentMethod{ public function getPaymentForm(Order $order): string{ $returnURL = "https://our-website.com/"."order/{$order->id}/payment/paypal/return"; return <<<FORM <form action="https://paypal.com/payment" method="POST"> <input type="hidden" id="email" value="{$order->email}"> <input type="hidden" id="total" value="{$order->total}"> <input type="hidden" id="returnURL" value="$returnURL"> <input type="submit" value="Pay on PayPal"> </form> FORM; } public function validateReturn(Order $order, array $data): bool{ echo "PayPalPayment: ...validating... "; // ... echo "Done!\n"; return true; } } /** * The client code. */ $controller = new OrderController(); echo "Client: Let's create some orders\n"; $controller->post( "/orders", ["email" => "me@example.com", "product" => "ABC Cat food (XL)", "total" => 9.95,]); $controller->post( "/orders", ["email" => "me@example.com", "product" => "XYZ Cat litter (XXL)", "total" => 19.95,]); echo "\nClient: List my orders, please\n"; $controller->get("/orders"); echo "\nClient: I'd like to pay for the second, show me the payment form\n"; $controller->get("/order/1/payment/paypal"); echo "\nClient: ...pushes the Pay button...\n"; echo "\nClient: Oh, I'm redirected to the PayPal.\n"; echo "\nClient: ...pays on the PayPal...\n"; echo "\nClient: Alright, I'm back with you, guys.\n"; $controller->get( "/order/1/payment/paypal/return"."?key=c55a3964833a4b0fa4469ea94a057152&success=true&total=19.95"); ``` </details> <br /> 输出 ``` Client: Let's create some orders Controller: POST request to /orders with {"email":"me@example.com","product":"ABC Cat food (XL)","total":9.95} Controller: Created the order #0. Controller: POST request to /orders with {"email":"me@example.com","product":"XYZ Cat litter (XXL)","total":19.95} Controller: Created the order #1. Client: List my orders, please Controller: GET request to /orders Controller: Here's all orders: { "id": 0, "status": "new", "email": "me@example.com", "product": "ABC Cat food (XL)", "total": 9.95 } { "id": 1, "status": "new", "email": "me@example.com", "product": "XYZ Cat litter (XXL)", "total": 19.95 } Client: I'd like to pay for the second, show me the payment form Controller: GET request to /order/1/payment/paypal Controller: here's the payment form: <form action="https://paypal.com/payment" method="POST"> <input type="hidden" id="email" value="me@example.com"> <input type="hidden" id="total" value="19.95"> <input type="hidden" id="returnURL" value="https://our-website.com/order/1/payment/paypal/return"> <input type="submit" value="Pay on PayPal"> </form> Client: ...pushes the Pay button... Client: Oh, I'm redirected to the PayPal. Client: ...pays on the PayPal... Client: Alright, I'm back with you, guys. Controller: GET request to /order/1/payment/paypal/return?key=c55a3964833a4b0fa4469ea94a057152&success=true&total=19.95 PayPalPayment: ...validating... Done! Controller: Thanks for your order! Order: #1 is now completed. ```