一个图书打折系统的设计

简介:
书店推出打折消息:
[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
 

本文转自zhangjunhd51CTO博客,原文链接:http://blog.51cto.com/zhangjunhd/64871,如需转载请自行联系原作者
相关文章
|
7月前
|
前端开发 Java 关系型数据库
超市商品管理系统的设计与实现(论文+源码)_kaic
超市商品管理系统的设计与实现(论文+源码)_kaic
|
4月前
|
算法 Java uml
设计一个网上书店,该系统中所有的计算机类图书(ComputerBook)每本都有10%的折扣,所有的语言类图书(LanguageBook)每本都有2元的折扣,小说类图书(NovelBook)每100元
该博客文章通过策略模式设计了一个网上书店系统,其中不同类型的图书(计算机类、语言类、小说类)应用不同的折扣策略,并通过Java代码示例展示了如何实现和应用这些策略来计算图书的折扣价格。
设计一个网上书店,该系统中所有的计算机类图书(ComputerBook)每本都有10%的折扣,所有的语言类图书(LanguageBook)每本都有2元的折扣,小说类图书(NovelBook)每100元
|
6月前
|
设计模式 前端开发 JavaScript
图书借阅系统开发笔记
图书借阅系统开发笔记
40 7
|
7月前
|
前端开发 JavaScript Java
孔夫子图书商城购物系统的设计与实现(论文+源码)_kaic
孔夫子图书商城购物系统的设计与实现(论文+源码)_kaic
|
7月前
|
SQL 开发框架 安全
超市商品信息管理系统设计与实现(论文+源码)_kaic
超市商品信息管理系统设计与实现(论文+源码)_kaic
|
SQL 前端开发 程序员
超市商品信息管理系统设计与实现(论文+源码)
本次主要先介绍研究背景、研究目标及相应价值的基础上,分析了国内外电子商务及相应超市管理系统的研究现状。随着计算机技术和网络技术的发展,顾客购买方式也从商店购买发展到超市管理系统。由于学生对商品的需求非常大,所以我想设计一个超市管理系统信息系统。
294 0
超市商品信息管理系统设计与实现(论文+源码)
|
算法 Python
算法创作|模拟商品加入购物车并结算价钱问题解决方法
算法创作|模拟商品加入购物车并结算价钱问题解决方法
108 0
算法创作|模拟商品加入购物车并结算价钱问题解决方法
《网上图书销售系统》功能需求
《网上图书销售系统》功能需求
169 0
《网上图书销售系统》功能需求 建立“顾客建立图书订单”的顺序图
《网上图书销售系统》功能需求 建立“顾客建立图书订单”的顺序图
175 0
|
测试技术
《网上图书销售系统》功能需求(类图)
《网上图书销售系统》功能需求(类图)
319 0