链表实战之超市购物车 | 带你学《Java面向对象编程》之九十六

简介: 本节结合在超市购买商品,商品放入购物车的实际情景,制定商品、购物车与收银台的标准并完成实现,基于链表来对这一复杂情景内的各种实体进行处理。

上一篇:链表实战之宠物商店 | 带你学《Java面向对象编程》之九十五
【本节目标】
通过阅读本节内容,你将借助链表这一工具,实现对更加复杂的现实情景的数据处理,进一步掌握链表的各类定义、实现以及运用手段。

综合实战:超市购物车

使用面向对象的概念表示出下面的生活场景:小明去超市买东西,所有买到的东西都放在了购物车,最后到收银员结账。

image.png
图一 超市购物设计实现

步骤:
1、定义商品标准
2、定义购物车标准
3、定义一个购物车的实现类
4、定义收银台
5、定义商品信息
图书:
书包:
6、进行代码测试的编写

interface ILink<E> {         //设置泛型避免安全隐患
       public void add(E e) ;   //增加数据
       public int size() ;    //获取数据的个数
       public boolean isEmpty() ;   //判断是否空集合
       public Object[] toArray() ;     //将集合元素以数组的形式返回
       public E get(int index) ;   //根据索引获取数据
       public void set(int index,E data) ;    //修改索引数据
       public boolean contains(E data) ; //判断数据是否存在
       public void remove(E e) ;        //数据删除
       public void clean() ;    //清空集合
}
class LinkImpl<E> implements ILink<E> {
      private class Node {         //保存节点的数据关系
              private E data ;      //保存数据
              private Node next ;       //保存下一个引用
              public Node(E data) {          //有数据的情况下才有意义
                     this.data = data ;
              }
                //第一次调用:this = LinkImpl.root ;
                //第二次调用:this = LinkImpl.root.next ;
                 //第三次调用:this = LinkImpl.root.next.next ;
              public void addNode(Node newNode){      //保存新的Node数据
                      if (this.next == null) {   //当前节点的下一个节点为null
                           this.next = newNode;      //保存当前节点
                      }else {
                           this.next.addNode(newNode);
                      }
               }
                //第一次调用:this = LinkImpl.root
                //第二次调用:this = LinkImpl.root.next
                /第三次调用:this = LinkImpl.root.next.next
               public void toArrayNode() {
                     LinkImpl.this.returnData [LinkImpl.this.foot ++] = this.data ;
                     if (this.next != null) {     //还有下一个数据
                          this.next.toArrayNode() ;
                    }
               }
               public E getNode(int index) {
                      if (LinkImpl.this.foot ++ == index) {       //索引相同
                           return this.data ;    //返回当前数据
                      }else {
                           return this.next.getNode(index) ;
                      }
               }
               public void setNode(int index,E data) {
                      if (LinkImpl.this.foot ++ == index) {       //索引相同
                           this.data = data ;    //修改数据
                      }else {
                            this.next.setNode(index,data) ;
                      }
               }
               public boolean containsNode(E data) {
                      if (data.equals(this.data)) {    //对象比较
                           return true ;
                     }else {
                           if (this.next == null) {         //没有后续节点
                                  return false ;   //找不到
                           }else {
                                  return this.next.containsNode(data) ;   //向后继续判断 
                           }
                     }
               }
               public void removeNode(Node<E> previous,E date) {
                      if (this.date.equals(date)) {
                           previous.next = this.next ;
                      }else {
                          if (this.next!=null) {
                                this.next.removeNode(this,date) ;
                          }
                      }
               }
               public void removeNode (Node previous,E data) {
                      if (this.data.equals(data)) {
                            previous.next = this.next ;    //空出当前节点
                      }else {
                            if (this.next != null) {       //有后续节点
                                 this.next.removeNode(this, data) ;    //向后继续删除
                           }
                     }
               }
      }
      //------------以下为Link类中定义的成员-----------------
      private Node root ;       //保存根元素
      private int count ;     //保存数据的个数
      private int foot ;     //描述的是操作数组的脚标
      private Object[] returnData ;   //返回的数据保存
      //------------以下为Link类中定义的方法-----------------
      public void add(E e){
         if(e == null){
             return ;
         }
        //数据本身是不具有关联特性的,只有Node类有,要想关联处理就必须将数据包装在Node类中
         Node newNode = new Node(e);    //创建一个新的节点
         if (this.root == null){            //现在没有根节点
            this.root = newNode;       //第一个节点作为根节点
         }else{                          //根节点存在
            this.root.addNode(newNode);       //将新节点保存在合适的位置
         }   
         this.count++ ;  
     }
     public int size() {
            return this.count ;
     }
     public boolean isEmpty() {
             //return this.root == null ;
             return this.count == 0 ;
     }
     public Object[] toArray() {
            if (this.isEmpty()) {           //空集合
                return null ;      //现在没有数据
            }
            this.foot = 0 ;  //脚标清零
            this.returnData = new Object[this.count] ;   //根据已有的长度开辟数组
            this.root.toArrayNode() ; //利用Node类进行递归数据获取
            return this.returnData ;
     }
     public E get(int index) {
           if (index >= this.count) {    //索引应该在指定的范围之内
                return null ;
           }    //索引数据的获取应该由Node类完成
           this.foot = 0 ;   //重置索引的下标
           return this.root.getNode(index) ;
     }
     public void set(int index,E data) {
             if (index >= this.count) {    //索引应该在指定的范围之内
                return  ;     //方法结束
           }    //索引数据的获取应该由Node类完成
           this.foot = 0 ;   //重置索引的下标
           this.root.setNode(index,data) ;  //修改数据
     }  
     public boolean contains(E data) {
            if (data == null) {
                 return false ;     //没有数据
            }
            return this.root.containsNode(data) ;    //交给Node类判断
     }
     public void remove(E data) {
            if (this.contains(data)) {     //判断数据是否存在
                  if (this.root.data.equals(data)) {       //根节点为要删除节点
                      this.root = this.root.next ;    //根的下一个节点  
                  }else {         //交由Node类进行删除
                       this.root.next.removeNode(this.root , data) ;
                  }
                  this.count -- ;
            }
     }
     public void clean() {
           this.root = null ;  //后续的所有节点都没了
           this.count = 0 ;   //个数清零
     }
}
interface IGoods{    //定义商品标准
    public String getName();
    public double getPrice();
}
interface IShopCar{       //购物车
    public void add(IGoods goods);   //添加商品信息
    public void delete(IGoods goods); //删除商品
    public Object [] getAll();   //获得购物车中全部商品信息
}
interface ICashier{
    public int getNumber();
    public double getPrice(); 
}
class ShopCarImpl implements IShopCar{   //购物车
    ILink<IGoods> allGoodseses = new LinkImpl<IGoods>() ;
    public void add(IGoods goods) {
        this.allGoodseses.add(goods);
    }
    public void delete(IGoods goods) {
        this.allGoodses.remove(goods);
    }
    public Object [] getAll() {
        return this.allGoodses.toArray();
    }
}
class Cashier {     //收银台
private IShopCar shopcar;
public Cashier(IShopCar shopcar) {
        this.shopcar = shopcar;
    }
public double allPrice() {    //计算总价
        double all =0.0;
    Object result [] = this.shopcar.getAll() ;
        for(Object obj : result) {
            IGoods goods = (IGoods)obj;
            all += goods.getPrice();
        }
        return all ;
}
public int allCount() {    //商品数量
       return this.shopcar.getAll().length;
}
 }
class Bag implements IGoods{
    private String name;
    private double price;
    public Bag(String name,double price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return this.name;
    }
    public double getPrice() {
        return this.price;
    }
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Bag)) {
            return false;
        }
        Bag bag = (Bag) obj;
        return this.name.equals(bag.name) && this.price == bag.price;
    }
    public String toString() {
        return "【背包信息】名称:"+this.name + "、价格:"+this.price;
    }
}
class Book implements IGoods {
    private String name ;
    private double price ;
    public Book(String name,double price) {
        this.name = name ;
        this.price = price ;
    }
    public String getName() {
        return this.name;
    }
    public double getPrice() {
        return this.price;
    }
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Book)) {
            return false;
        }
        Book book = (Book) obj;
        return this.name.equals(book.name) && this.price == book.price;
    }
    public String toString() {
        return "【图书信息】名称:"+this.name + "、价格:"+this.price;
    }
}
public class JavaDemo{
    public static void main(String args[]) {
        IShopcar car = new ShopCarImpl();
        car.add(new Book("Java开发",79.8));
        car.add(new Book("Oracle ",89.8));
        car.add(new Bag("小强背包",889.8));
        Cashier cas = new Cashier(car);
        System.out.println("总价格:"+cas.allPrice ()+"、购买总数量:"+cas.allCount ());
    }
}

image.png
图二 执行结果图

整体代码都是基于链表的功能实现的。
想学习更多的Java的课程吗?从小白到大神,从入门到精通,更多精彩不容错过!免费为您提供更多的学习资源。
本内容视频来源于阿里云大学

下一篇:认识开发利器-Eclipse | 带你学《Java面向对象编程》之九十七
更多Java面向对象编程文章查看此处

相关文章
|
29天前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
60 2
|
1月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
1月前
|
开发框架 Java 程序员
揭开Java反射的神秘面纱:从原理到实战应用!
本文介绍了Java反射的基本概念、原理及应用场景。反射允许程序在运行时动态获取类的信息并操作其属性和方法,广泛应用于开发框架、动态代理和自定义注解等领域。通过反射,可以实现更灵活的代码设计,但也需注意其性能开销。
47 1
|
2月前
|
缓存 负载均衡 Dubbo
Dubbo技术深度解析及其在Java中的实战应用
Dubbo是一款由阿里巴巴开源的高性能、轻量级的Java分布式服务框架,它致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
77 6
|
2月前
|
Java
领略Lock接口的风采,通过实战演练,让你迅速掌握这门高深武艺,成为Java多线程领域的武林盟主
领略Lock接口的风采,通过实战演练,让你迅速掌握这门高深武艺,成为Java多线程领域的武林盟主
36 7
|
2月前
|
Java 数据中心 微服务
Java高级知识:线程池隔离与信号量隔离的实战应用
在Java并发编程中,线程池隔离与信号量隔离是两种常用的资源隔离技术,它们在提高系统稳定性、防止系统过载方面发挥着重要作用。
45 0
|
2月前
|
消息中间件 缓存 Java
RocketMQ的JAVA落地实战
RocketMQ作为一款高性能、高可靠、高实时、分布式特点的消息中间件,其核心作用主要体现在异步处理、削峰填谷以及系统解耦三个方面。
175 0
【Java数据结构】经典链表OJ题——超详细做题笔记及心得(二)
【Java数据结构】经典链表OJ题——超详细做题笔记及心得(每行代码都有注释嗷)
【Java数据结构】经典链表OJ题——超详细做题笔记及心得(二)
【Java数据结构】经典链表OJ题——超详细做题笔记及心得(一)
【Java数据结构】经典链表OJ题——超详细做题笔记及心得(每行代码都有注释嗷)
【Java数据结构】经典链表OJ题——超详细做题笔记及心得(一)
|
12天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。