Классы Cartltem и ShoppingCart
Минимальным требованием к объекту, представляющему товар в корзине покупателя, является наличие идентификатора данного товара и количества заказанных экземпляров. Название товара, его цену и другие сведения можно найти в каталоге — документе XML. Но мы решили не ограничиваться минимальными требованиями и добавили в Cartltem название товара, цену и информацию по доставке, как показано в листинге 4.1.
Следует отметить несколько важных моментов, касающихся класса Cartltem. Во-первых, конструктор работает непосредственно с объектом El ement структуры DOM, представляющим данный товар. Это упрощает добавление различных дополнительных переменных в XML-каталог. Во-вторых, класс Cartltem реализует интерфейс Serializable. Это позволяет посылать коллекцию объектов Cartltem, представляющую собой список заказанных товаров, другой программе Java, используя сериализацию данных. Сериализация также требуется, если процессору сервлетов приходится хранить сеанс или пересылать его на другой сервер. Наконец, названия методов доступа, например getld и setNumberOrdered, соответствуют соглашению об именах, принятому в JavaBeans, чтобы упростить использование объекта Cartltem в коде JSP-страницы.
Листинг 4.1. Класс Cartltem (cartltem.java) [Все представленные в книге тексты программ можно найти на сайте издательства по адресу www.piter.com. — Примеч. ред. ]
package com.XmlEcomBook.catalog;
import java.util.* ;
import java.io.* ;
import org.xml.sax.* ;
import org.w3c.dom.* ;
public class CartItem implements java.io.Serializable
{ // be sure to change this if substantive variables change
static final long serialVersionUID = 3260689382642549142L;
// these are set from the constructor
private String id ; // from product element
private String name ; // from name element
private String price ; // from price element
private String shippingType ; // from shipping_info element
private String shippingValue ; // may be null if type is special
// these may change
private int numberOrdered ; // changes
public String getId(){ return id ;}
public String getName(){ return name ; }
public String getPrice() { return price ; }
public String getShippingType() { return shippingType ; }
public String getShippingValue() { return shippingValue ; }
public int getNumberOrdered(){ return numberOrdered ; }
public void setId(String s){ id = s ; }
public void setName(String s){ name = s; }
public void setPrice(String s){ price = s ;}
public void setShippingType(String s ){shippingType = s ;}
public void setShippingValue(String s) { shippingValue = s ;}
public void setNumberOrdered( int n ){ numberOrdered = n ;
System.out.println("setNumberOrdered " + n );
}
// needed for operation as a Bean
public CartItem(){
}
// constructor uses a <product> org.w3c.dom.Element
public CartItem( Element pe ){
id = pe.getAttribute("id");
NodeList nl = pe.getElementsByTagName( "name" );
name = nl.item(0).getFirstChild().getNodeValue() ;
nl = pe.getElementsByTagName( "price" );
price = nl.item(0).getFirstChild().getNodeValue() ;
nl = pe.getElementsByTagName( "shipping_info" );
Element ship = (Element) nl.item(0);
shippingType = ship.getAttribute("type");
shippingValue = ship.getAttribute("value"); // may be ""
}
// handy for debugging
public String toString() {
StringBuffer sb = new StringBuffer("CartItem name:");
sb.append( name ); sb.append(" numberOrdered: ");
sb.append( Integer.toString( numberOrdered ));
return sb.toString();
}
}
Класс ShoppingCart достаточно прост, так как все, что от него требуется, — манипулирование объектами класса Cartltem. Как показано в листинге 4.2, мы храним ссылки на объекты Cartltem в двух местах — Vector и HashTable. Причина этого заключается в том, что порядок размещения ссылок в объекте HashTable непредсказуем и может меняться по мере добавления новых товаров. Представляется разумным хранить эти ссылки в предсказуемой и воспроизводимой последовательности в объекте Vector и в то же время иметь возможность доступа к товарам по их идентификаторам через хэш-таблицу.
Заметим, что класс ShoppingCart реализует интерфейс Serializable, так что вся корзина (то есть объект класса Shoppi ngCart) может пересылаться между программами Java или записываться в файл посредством сериализации.
Листинг 4.2. Начало кода класса ShoppingCart (ShoppingCart.java)
package com.XmlEcomBook.catalog;
import java.io.*;
import java.util.* ;
public class ShoppingCart implements java.io.Serializable
{ private Vector items ; // maintains order of selection of items
private Hashtable itemsById ;
public ShoppingCart(){
items = new Vector();
itemsById = new Hashtable();
}
// items vector may be empty
public Vector getItems(){ return items ; }
// returns CartItem for this id or null if not in list
public CartItem getProdById(String s ){
return (CartItem) itemsById.get( s );
}
// CartItem is assumed to be unique
public int addItem( CartItem x ){
items.addElement( x );
itemsById.put( x.getId() , x );
return items.size();
}
В листинге 4.3 показаны остальные методы класса ShoppingCart. Поскольку мы храним ссылки на объекты Cartltem в двух коллекциях, для удаления элемента из объекта HashTable применяется метод removeByld с указанием идентификатора товара и затем вызывается метод removeEl eraent вектора items.
Листинг 4.3. Остальная часть кода класса ShoppingCart (ShoppingCart.java)
// remove an item from the cart by product id
public CartItem removeById( String s ){
CartItem ret = (CartItem)itemsById.get( s );
if( ret == null ) return null ;
itemsById.remove(s); // remove by key
items.removeElement( ret );
return ret ;
}
// remove all CartItem for which the numberOrdered is zero
// returns the count of items left
public int removeEmptyItems(){
Enumeration keys = itemsById.keys();
while( keys.hasMoreElements()){
String key = (String)keys.nextElement();
CartItem ci = (CartItem)itemsById.get(key);
if( ci.getNumberOrdered() == 0 ){
removeById( key );
}
}
return items.size();
}
// mainly for debugging
public String toString()
{ StringBuffer sb = new StringBuffer( "ShoppingCart has " +
items.size() + " items.\r\n" ) ;
Enumeration e = items.elements();
while( e.hasMoreElements()){
sb.append("Item: ");
sb.append( e.nextElement().toString() );
sb.append("\r\n");
}
return sb.toString();
}
}