美文网首页
设计模式实际应用之购物车

设计模式实际应用之购物车

作者: zxhnext | 来源:发表于2019-09-22 22:46 被阅读0次

    1. 类图

    image.png

    2. 用到的设计模式

    ◆工厂模式 单例模式
    ◆装饰器模式 观察者模式
    ◆状态模式 模板方法模式 代理模式

    3. 目录结构

    ├── src
    |    ├── api // 购物车列表接口
    |        ├── list.json
    |    ├── config // 配置文件
    |        ├── config.js
    |    ├── Item // 列表中的每一项
    |        ├── CreateItem.js
    |        └── Item.js
    |    ├── List // 商品列表
    |        ├── List.js
    |    ├── ShoppingCart // 购物车
    |        ├── GetCart.js
    |        └── ShoppingCart.js
    |    ├── util
    |        ├── logs.js // 日志
    |    ├── App.js
    |    ├── index.js // 入口
    |    ├── index.html
    |    ├── webpack.config.js
    

    http-server -p 8080

    4. 各模块用到的设计模式

    ◆工厂模式:$('xxx'),创建商品
    ◆单例模式:购物车
    ◆装饰器模式:打点统计

    ◆观察者模式:网页事件,Promise
    ◆状态模式:添加到购物车&从购物车删除
    ◆模板方法模式:渲染有统一的方法,内部包含了各模块渲染

    ◆代理模式:打折商品信息处理

    5. 代码实现

    index.html

    <body>
        <div id="app"></div>
    </body>
    

    index.js(入口)

    import App from './demo/App.js'
    
    let app = new App('app')
    app.init() // 初始化
    

    App.js

    import $ from 'jquery'
    import ShoppingCart from './ShoppingCart/ShoppingCart.js'
    import List from './List/List.js'
    
    export default class App {
        constructor(id) {
            this.$el = $(`#${id}`)
        }
    
        // 初始化购物车
        initShoppingCart() {
            let shoppingCart = new ShoppingCart(this)
            shoppingCart.init()
        }
    
        // 初始化商品列表
        initList() {
            let list = new List(this)
            list.init()
        }
    
        init() { // 初始化
            this.initShoppingCart()
            this.initList()
        }
    }
    

    List.js(商品列表)

    import $ from 'jquery'
    import createItem from '../Item/CreateItem.js'
    import { GET_LIST } from '../config/config.js'
    
    export default class List {
        constructor(app) {
            this.app = app
            this.$el = $('<div>')
        }
    
        // 获取数据
        loadData() {
            // 使用 fetch (低版本浏览器可使用 https://github.com/github/fetch 兼容)
            // 返回 promise
            return fetch(GET_LIST).then(result => {
                return result.json()
            })
        }
    
        // 生成列表
        initItemList(data) {
            data.map(itemData => {
                let item = createItem(this, itemData)
                item.init()
                return item
            })
        }
    
        // 渲染
        render() {
            this.app.$el.append(this.$el)
        }
    
        init() { // 初始化列表
            this.loadData().then(data => {
                this.initItemList(data)
            }).then(() => {
                // 最后再一起渲染 DOM ,以避免重复渲染的性能问题
                this.render()
            })
        }
    }
    

    Item(列表中的每一项)

    // CreateItem.js
    import Item from './Item.js'
    
    function createDiscount(item) {
        // 用代理做折扣显示
        return new Proxy(item, {
            get: function (target, key, receiver) {
                if (key === 'name') {
                    return `${target[key]}【折扣】`
                }
                if (key === 'price') {
                    return target[key] * 0.8
                }
                return target[key]
            }
        })
    }
    
    // 工厂函数
    export default function (list, itemData) {
        if (itemData.discount) {
            itemData = createDiscount(itemData)
        }
        return new Item(list, itemData)
    }
    
    // Item.js
    import $ from 'jquery'
    import StateMachine from 'javascript-state-machine'
    import { log } from '../util/log.js'
    import getCart from '../ShoppingCart/GetCart.js'
    
    export default class Item {
        constructor(list, data) {
            this.list = list
            this.data = data
            this.$el = $('<div>')
            this.cart = getCart()
        }
    
        initContent() { // 列表内容
            let $el = this.$el
            let data = this.data
            $el.append($(`<p>名称:${data.name}</p>`))
            $el.append($(`<p>价格:${data.price}</p>`))
        }
    
        initBtn() { // 按钮
            let $el = this.$el
            let $btn = $('<button>')
    
            // 状态管理
            let _this = this
            let fsm = new StateMachine({
                init: '加入购物车',
                transitions: [
                    {
                        name: 'addToCart', 
                        from: '加入购物车',
                        to: '从购物车删除'
                    },
                    {
                        name: 'deleteFromCart',
                        from: '从购物车删除',
                        to: '加入购物车'
                    }
                ],
                methods: {
                    // 加入购物车
                    onAddToCart: function () {
                        _this.addToCartHandle()
                        updateText()
                    },
                    // 删除
                    onDeleteFromCart: function () {
                        _this.deleteFromCartHandle()
                        updateText()
                    }
                }
            })
            function updateText() {
                $btn.text(fsm.state)
            }
    
            $btn.click(() => {
                if (fsm.is('加入购物车')) {
                    fsm.addToCart()
                } else {
                    fsm.deleteFromCart()
                }
            })
            updateText()
    
            $el.append($btn)
        }
    
        // 加入购物车
        @log('add') // 日志
        addToCartHandle() {
            this.cart.add(this.data)
        }
    
        // 从购物车删除
        @log('del') // 日志
        deleteFromCartHandle() {
            this.cart.del(this.data.id)
        }
    
        render() {
            this.list.$el.append(this.$el)
        }
    
        init() {
            this.initContent()
            this.initBtn()
            this.render()
        }
    }
    

    ShoppingCart(购物车)

    // GetCart.js
    class Cart {
        constructor() {
            this.list = []
        }
        add(data) { // 添加
            this.list.push(data)
        }
        del(id) { // 删除
            this.list = this.list.filter(item => {
                if (item.id === id) {
                    return false
                }
                return true
            })
        }
        getList() { // 获取购物车列表
            return this.list.map(item => {
                return item.name
            }).join('\n')
        }
    }
    
    // 返回单例
    let getCart = (function () {
        let cart
        return function () {
            if (!cart) {
                cart = new Cart();
            }
            return cart
        }
    })()
    
    export default getCart
    
    // ShoppingCart.js
    import $ from 'jquery'
    import getCart from './GetCart.js'
    
    export default class ShoppingCart {
        constructor(app) {
            this.app = app
            this.$el = $('<div>').css({
                'padding-bottom': '10px',
                'border-bottom': '1px solid #ccc'
            })
            this.cart = getCart()
        }
    
        // 显示购物车内容
        showCart() {
            alert(this.cart.getList())
        }
    
        // 初始化按钮
        initBtn() {
            let $btn = $('<button>购物车</button>')
            $btn.click(() => {
                this.showCart()
            })
            this.$el.append($btn)
        }
    
        // 渲染
        render() {
            this.app.$el.append(this.$el)
        }
    
        init() {
            this.initBtn()
            this.render()
        }
    }
    

    log.js(日志)

    export function log(type) {
        return function (target, name, descriptor) {
            var oldValue = descriptor.value;
        
            descriptor.value = function() {
                //  此处统一上报日志
                console.log(`日志上报 ${type}`);
        
                // 执行原有方法
                return oldValue.apply(this, arguments);
            };
        
            return descriptor;
        }
    }
    

    config.js(配置文件)

    export const GET_LIST = '/api/list.json'
    

    list.json(列表接口)

    [
        {
            "id": 1,
            "name": "《JS 基础面试题》",
            "price": 149,
            "discount": 1
        },
        {
            "id": 2,
            "name": "《JS 高级面试题》",
            "price": 366,
            "discount": 1
        },
        {
            "id": 3,
            "name": "《React 模拟大众点评 webapp》",
            "price": 248,
            "discount": 0
        },
        {
            "id": 4,
            "name": "《zepto 设计与源码解读》",
            "price": 0,
            "discount": 0
        }
    ]
    

    相关文章

      网友评论

          本文标题:设计模式实际应用之购物车

          本文链接:https://www.haomeiwen.com/subject/zzryuctx.html