書店推出打折消息:
[1]對於“新書”,沒有折扣;
[2]對於“計算機”類圖書,固定折扣為10元;
[3]對於“經管”類圖書,折扣的書價的10%;
[4]購買5本以上的圖書,固定折扣為20元;
[5]在所有的折扣計算後,總的折扣價不得超過50元。
1.使用Strategy模式
對於打折消息[1],[2],[3]針對三種類型的圖書,可以使用Strategy模式。
NoDiscountStrategy代表購買“新書”的打折策略-沒有折扣;
FlatRateStrategy代表購買“計算機”類圖書的打折策略-固定折扣價;
PercentageStrategy代表購買“經管”類圖書的打折策略-百分比折扣價。
<<abstract>>DiscountStrategy.java
package com.zj.books.strategy;
public abstract class DiscountStrategy {
protected double _price = 0.0;
public DiscountStrategy(double price) {
_price = price;
}
abstract public double calculateDiscount();
……
}
_price代表圖書的價格;抽象方法calculateDiscount()表示具體的打折計算邏輯,延遲到子類中實現。下面的三個子類的部分邏輯。
NoDiscountStrategy.java
package com.zj.books.strategy;
public class NoDiscountStrategy extends DiscountStrategy {
public NoDiscountStrategy(double price) {
super(price);
}
public double calculateDiscount() {
return 0.0;
}
}
FlatRateStrategy.java
package com.zj.books.strategy;
public class FlatRateStrategy extends DiscountStrategy {
private double _discount = 0.0;
public FlatRateStrategy(double price, double discount) {
super(price);
_discount = discount;
}
public double calculateDiscount() {
return _discount;
}
……
}
PercentageStrategy.java
package com.zj.books.strategy;
public class PercentageStrategy extends DiscountStrategy {
private double _percent = 1.0;
public PercentageStrategy(double price, double percent) {
super(price);
if (percent > 1.0)
percent = 1.0;
_percent = percent;
}
public double calculateDiscount() {
return _price * _percent;
}
……
}
使用一個抽象基類Book持有一個策略引用,這個策略是抽象基類的引用。這個類中提供一個重要的方法getDiscount(),通過分配的具體策略的_strategy.calculateDiscount()方法來得到折扣。而如何實現Book具體子類與Strategy具體子類的配對,將使用工廠方法模式。
<<abstract>> Book.java
package com.zj.books;
import com.zj.books.strategy.DiscountStrategy;
public abstract class Book {
protected String _name;
protected int _typeCode;
protected double _price;
protected DiscountStrategy _strategy;
public Book(String name, int bookType, double price) {
_name = name;
_typeCode = bookType;
_price = price;
}
public double getDiscount() {
return _strategy.calculateDiscount();
}
……
}
2.使用 Factory Method模式
對於策略的分配,使用Factory Method模式。這樣對於書的種類和打折策略都是可以擴展的。
三個具體的Publish類分別針對三種類型的書和三種打折策略,給出具體的對象。
<<interface>> Publisher.java
package com.zj.purchase;
import com.zj.books.Book;
public interface Publisher {
Book bookFactory(String name,double price);
}
三個具體的子類實現bookFactory方法,分別生成配對的具體Book類和具體Strategy類。
ComputerBookPublish.java
package com.zj.purchase;
import com.zj.books.Book;
import com.zj.books.ComputerBook;
import com.zj.books.strategy.FlatRateStrategy;
public class ComputerBookPublish implements Publisher{
private double _discount=0.0;
public ComputerBookPublish(double discount){
_discount=discount;
}
public Book bookFactory(String name,double price) {
Book book=new ComputerBook(name,price);
book.setStrategy(new FlatRateStrategy(price, _discount));
return book;
}
……
}
ManagementBookPublish.java
package com.zj.purchase;
import com.zj.books.Book;
import com.zj.books.ManagementBook;
import com.zj.books.strategy.PercentageStrategy;
public class ManagementBookPublish implements Publisher{
private double _percent=1.0;
public ManagementBookPublish(double percent){
_percent=percent;
}
public Book bookFactory(String name,double price) {
Book book=new ManagementBook(name,price);
book.setStrategy(new PercentageStrategy(price, _percent));
return book;
}
……
}
NewReleaseBookPublisher.java
package com.zj.purchase;
import com.zj.books.Book;
import com.zj.books.NewReleaseBook;
import com.zj.books.strategy.NoDiscountStrategy;
public class NewReleaseBookPublisher implements Publisher{
public Book bookFactory(String name,double price) {
Book book=new NewReleaseBook(name,price);
book.setStrategy(new NoDiscountStrategy(price));
return book;
}
}
3.使用Decorate模式
對於[4]和[5]可使用Decorate模式實現。
Order類是一個接口,定義了所有客戶端可以使用的行為。其中buy()方法表示購買書,其中的參數依次表示冊數,書名,單價,和圖書類型;originalPay()方法表示原始貨款;actualPay()表示實際貨款;discount()表示折扣;addPolicy()方法將被應用於Decorate模式。
<<interface>>Order.java
package com.zj.order;
public interface Order {
void buy(int copies,String name,int price,int type);
double originalPay();
double actualPay();
void setActualPay(double pay);
double discount();
void setDiscount(double discount);
int getCopies();
void printPayList();
void addPolicy();
}
PayOrder類是一個基於打折消息[1],[2],[3]的應用,在buy()方法中,根據具體的圖書類型,產生一個具體的publisher類,繼而可以獲得相應的圖書實例及折扣策略實例。
PayOrder.java
package com.zj.order;
import java.util.HashMap;
import java.util.Map;
import com.zj.books.Book;
import com.zj.books.BookType;
import com.zj.purchase.ComputerBookPublish;
import com.zj.purchase.ManagementBookPublish;
import com.zj.purchase.NewReleaseBookPublisher;
public class PayOrder implements Order {
private Map<String, Integer> payList = new HashMap<String, Integer>();
private double _pay = 0.0;
private double _discount = 0.0;
private int _copies = 0;
private double _discountPolicy = 0.0;
private double _percentagePolicy = 1.0;
public PayOrder(double discountPolicy, double percentagePolicy) {
_discountPolicy = discountPolicy;
_percentagePolicy = percentagePolicy;
}
public void buy(int copies, String name, int price, int type) {
Book book = null;
switch (type) {
case BookType.NEW_RELEASE:
book = new NewReleaseBookPublisher().bookFactory(name, price);
break;
case BookType.COMPUTER:
book = new ComputerBookPublish(_discountPolicy).bookFactory(name,
price);
break;
case BookType.MANAGEMENT:
book = new ManagementBookPublish(_percentagePolicy).bookFactory(
name, price);
break;
default:
throw new RuntimeException("Type not found.");
}
_copies += copies;
payList.put(book.getName(), copies);
_pay += copies * book.getPrice();
_discount += copies * book.getDiscount();
}
public double originalPay() {
return _pay;
}
public double actualPay() {
return _pay - _discount;
}
public void setActualPay(double pay) {
_pay = pay;
}
public double discount() {
return _discount;
}
public void setDiscount(double discount) {
_discount = discount;
}
public int getCopies() {
return _copies;
}
public void printPayList() {
System.out.println(toString());
}
public void addPolicy() {
}
public String toString() {
return payList.toString();
}
}
OrderDecorator是一個裝飾角色,它持有一個Order的引用。
OrderDecorator.java
package com.zj.order.decorator;
import com.zj.order.Order;
public class OrderDecorator implements Order {
protected Order _order;
public OrderDecorator(Order order) {
_order = order;
}
public double actualPay() {
return _order.actualPay();
}
public void setActualPay(double pay) {
_order.setActualPay(pay);
}
public void buy(int copies, String name, int price, int type) {
_order.buy(copies, name, price, type);
}
public double discount() {
return _order.discount();
}
public void setDiscount(double discount) {
_order.setDiscount(discount);
}
public double originalPay() {
return _order.originalPay();
}
public int getCopies() {
return _order.getCopies();
}
public void printPayList(){
_order.printPayList();
}
public void addPolicy(){
_order.addPolicy();
}
}
根據打折消息[4]:“購買5本以上的圖書,固定折扣為20元”,得到具體裝飾角色CopyDecorator。它將重寫addPolicy()方法。
CopyDecorator.java
package com.zj.order.decorator;
import com.zj.order.Order;
public class CopyDecorator extends OrderDecorator {
public CopyDecorator(Order order) {
super(order);
}
public void addPolicy() {
if (getCopies() > 5)
setDiscount(discount() + 20);
super._order.addPolicy();
}
}
根據打折消息[5]:“在所有的折扣計算後,總的折扣價不得超過50元”,得到具體裝飾角色PayDecorator。它將重寫addPolicy()方法。
必須注意兩個裝飾類產生的先後順序。
PayDecorator.java
package com.zj.order.decorator;
import com.zj.order.Order;
public class PayDecorator extends OrderDecorator {
public PayDecorator(Order order) {
super(order);
}
public void addPolicy() {
if (discount() > 50)
setDiscount(50);
super._order.addPolicy();
}
}
4.客戶端實現
Client中先演示了沒有裝飾類,即只實現打折消息[1],[2],[3]的情況,此時原價300元的貨款折扣為36元;而後加上了兩個裝飾類後,由於購買六本書,另加29元折扣後總折扣變為56,超過50元的折扣上限,所以最終折扣為50元。
Client.java
package com.zj.client; import com.zj.books.BookType; import com.zj.order.Order; import com.zj.order.PayOrder; import com.zj.order.decorator.CopyDecorator; import com.zj.order.decorator.PayDecorator; public class Client { public static void main(String[] args) { Order order = new PayOrder(10, 0.1); order.buy(1, "Java", 40, BookType.COMPUTER); order.buy(1, "C++", 60, BookType.COMPUTER); order.buy(1, "Design Pattern", 100, BookType.COMPUTER); order.buy(1, "Manager", 60, BookType.MANAGEMENT); order.buy(1, "Apo", 20, BookType.NEW_RELEASE); order.buy(1, "droAq", 20, BookType.NEW_RELEASE); order.printPayList(); System.out.println("==========="); System.out.println("original\t"+order.originalPay()); System.out.println("discount\t"+order.discount()); System.out.println("actual\t\t"+order.actualPay()); System.out.println("==========="); order=new CopyDecorator(new PayDecorator(order)); order.addPolicy(); System.out.println("original\t"+order.originalPay()); System.out.println("discount\t"+order.discount()); System.out.println("actual\t\t"+order.actualPay()); } }
結果
{Apo=1, Manager=1, droAq=1, C++=1, Design Pattern=1, Java=1}
===========
original 300.0
discount 36.0
actual 264.0
===========
original 300.0
discount 50.0
actual 250.0
本文出自 “子 孑” 博客,請務必保留此出處http://zhangjunhd.blog.51cto.com/113473/64871