Java 根据用户的选择更改JLabel

Java 根据用户的选择更改JLabel,java,netbeans,jlabel,jcheckbox,jradiobutton,Java,Netbeans,Jlabel,Jcheckbox,Jradiobutton,我的任务是做一个简单的订单系统。我想要JLabel金额:$0.00显示用户选择的汉堡和调味品的相应金额。例如,如果用户单击牛肉,标签将变为金额:$4.00,当用户选择调味品时,标签将根据他选择的调味品数量向总金额增加0.50美元,反之亦然。此外,当用户取消选中调味品Jcheckbox时,它将从总数中扣除0.50美元。非常感谢您的帮助。非常感谢。 我的牛肉单选按钮代码: private void beef_radioBtnActionPerformed(java.awt.event.Action

我的任务是做一个简单的订单系统。我想要JLabel金额:$0.00显示用户选择的汉堡和调味品的相应金额。例如,如果用户单击牛肉,标签将变为金额:$4.00,当用户选择调味品时,标签将根据他选择的调味品数量向总金额增加0.50美元,反之亦然。此外,当用户取消选中调味品Jcheckbox时,它将从总数中扣除0.50美元。非常感谢您的帮助。非常感谢。

我的牛肉单选按钮代码:

private void beef_radioBtnActionPerformed(java.awt.event.ActionEvent evt) {                                              
        total_amount.setText("Amount: $4.00");
        ketchup_Checkbox.setEnabled(true);
        mustard_Checkbox.setEnabled(true);
        pickles_Checkbox.setEnabled(true);
    }  
番茄酱复选框代码:

private void ketchup_CheckboxActionPerformed(java.awt.event.ActionEvent evt) {                                                 
        float condiments_amount = (float) 0.50;
        float beef_amount = (float) 4.00;
        float total;
        if (beef_radioBtn.isSelected()){
            total = beef_amount + condiments_amount;
            total_amount.setText("Amount: $" + decimal.format(total));
            if (!ketchup_Checkbox.isSelected()){
                total_amount.setText("Amount: $" + decimal.format(4.50 - condiments_amount)); 
            }
            else if (mustard_Checkbox.isSelected()){
                total_amount.setText("Amount: $" + decimal.format(4.50 + condiments_amount));
            } 
            else if (pickles_Checkbox.isSelected()){
                total_amount.setText("Amount: $" + decimal.format(4.50 + condiments_amount));
            }
        }
     }

好的,系好安全带,这将是一段旅程

模型的概念是您可以使用的最强大的概念之一。一个模型只是一个模型,是一种分离程序不同区域的方法。因此,一个模型,对数据进行建模,将其视为一个容器,然后视图将使用这些模型对数据进行格式化,以便用户分离关注点。模型还可以包含业务逻辑或根据其需求执行计算

允许您集中概念,这样您就不会重复自己或忘记做事。这也是一种改变程序部分工作方式的方法,也称为委派

起点,一些接口 好吧,那是很多废话,让我们开始吧。我更喜欢使用接口来描述事物,它提供了很多自由,因为您可以将不同的接口放在一起以满足不同的需求

菜单 好的,简单的概念,这是一个可以出售的物品清单

public interface Menu {
    public List<MainMenuItem> getMenuItems();
}
主菜单项 这些都是顶级的独立菜单项,在我们的例子中,可以有调味品:D

public interface MainMenuItem extends MenuItem {
    public List<Condiment> getCondiments();
}
汉堡 这只是你可以做的一些事情的一个演示,汉堡包并没有什么特别之处,但正如你将看到的,我们可以用这个概念做不同的事情

public interface Burger extends MainMenuItem {
}
顺序 最后是订单,我们点了什么,我们想要什么调味品

public interface Order {
    public MainMenuItem getItem();
    public void setItem(MainMenuItem item);
    public List<Condiment> getCondiments();
    public void addCondiment(Condiment condiment);
    public void removeCondiment(Condiment condiment);
    public double getTally();
}
好的,试着不要太沉迷于此,但是看看这里抽象的用法。AbstractMenuItem封装了所有MenuItem实现都将需要的许多常见功能,所以我们不需要重复自己,亲爱的

其中一些实现已经在做出决策或应用规则。例如,当主菜单项发生更改时,DefaultOrder将清除调味品。它还可以确保所使用的调味品实际上可用于该项目

还要注意的是,tally方法不是存储的属性,但每次调用它时都会重新计算。这是一个设计决策,要将其变成一个存储属性并不难,因此每次更改MenuMenuItem、添加和/或删除调味品时,该属性都会更新,但我感觉很懒。但是你可以看到这些东西是如何改变的,它会影响这些模型的所有用户,sweet:D

好吧,但这究竟是如何回答这个问题的呢?嗯,实际上有点

所以,这个想法是,你从一张空白订单开始。用户选择一个主要项目,即汉堡,您将其设置为订单,然后更新UI作为响应。UI要求订单计算理货,并将其呈现给用户

此外,同样的概念也适用于调味品。每次用户添加或删除调味品时,订单都会更新,用户也会更新UI

好吧,但也许,举个例子更容易理解

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                List<Condiment> condiments = new ArrayList<>(3);
                condiments.add(new DefaultCondiment("Ketchup", 0.5));
                condiments.add(new DefaultCondiment("Mustard", 0.5));
                condiments.add(new DefaultCondiment("Pickles", 0.5));

                DefaultMenu menu = new DefaultMenu();
                menu.add(new DefaultBurger("Beef", 4.0, condiments));
                menu.add(new DefaultBurger("Chicken", 3.5, condiments));
                menu.add(new DefaultBurger("Veggie", 4.0, condiments));

                MenuPane menuPane = new MenuPane();
                menuPane.setMenu(menu);

                frame.add(menuPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MenuPane extends JPanel {

        private Menu menu;
        private Order order;
        private List<Condiment> selectedCondiments = new ArrayList<>();

        private JPanel burgerPanel;
        private JPanel condimentPanel;
        private JPanel totalPanel;

        private JLabel totalLabel;
        private JButton clearButton;
        private JButton payButton;

        private NumberFormat currencyFormatter;

        public MenuPane() {
            setLayout(new GridBagLayout());

            order = new DefaultOrder();

            burgerPanel = new JPanel();
            burgerPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
            condimentPanel = new JPanel();
            condimentPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
            totalPanel = makeTotalPanel();
            totalPanel.setBorder(new EmptyBorder(8, 8, 8, 8));

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.weightx = 1;
            gbc.weighty = 0.5;

            add(burgerPanel, gbc);

            gbc.gridy++;
            add(condimentPanel, gbc);

            gbc.gridy++;
            gbc.weighty = 0;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(totalPanel, gbc);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 200);
        }

        protected NumberFormat getCurrentFormatter() {
            if (currencyFormatter != null) {
                return currencyFormatter;
            }
            currencyFormatter = NumberFormat.getCurrencyInstance();
            currencyFormatter.setMinimumFractionDigits(2);
            return currencyFormatter;
        }

        protected JPanel makeTotalPanel() {
            JPanel totalPanel = new JPanel(new GridBagLayout());
            totalLabel = new JLabel();
            clearButton = new JButton("CLR");
            payButton = new JButton("PAY");

            clearButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    order = new DefaultOrder();
                    buildCondiments();
                    orderDidChange();
                }
            });

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.gridx = 0;
            gbc.gridy = 0;
            totalPanel.add(totalLabel, gbc);

            gbc.weightx = 0;
            gbc.gridx++;
            totalPanel.add(clearButton, gbc);
            gbc.gridx++;
            totalPanel.add(payButton, gbc);
            return totalPanel;
        }

        protected void buildBurgerMenu() {
            burgerPanel.removeAll();
            burgerPanel.setLayout(new GridBagLayout());
            if (menu == null) {
                return;
            }

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.weightx = 1;

            ButtonGroup bg = new ButtonGroup();

            // Stick with me, this is a little more advanced, but provides
            // a really nice concept and ease of use
            // We could also make use of the Action API, but that might
            // pushing you just a little to far ;)
            ActionListener actionListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!(e.getSource() instanceof JComponent)) {
                        return;
                    }
                    JComponent comp = (JComponent) e.getSource();
                    Object obj = comp.getClientProperty("MenuItem");
                    // I'm putting this here to demonstrate part of the concept
                    // of polymorphism - techncially, we don't have to care
                    // of it's a burger or some other type of menu item,
                    // only that this is going to represent the "main" item
                    if (!(obj instanceof MainMenuItem)) {
                        return;
                    }
                    MainMenuItem item = (MainMenuItem) obj;
                    order.setItem(item);

                    buildCondiments();
                    orderDidChange();
                }
            };

            System.out.println(menu.getMenuItems().size());
            for (MenuItem item : menu.getMenuItems()) {
                // Only interested in burgers
                // Could have the Menu do this, but that's a design
                // decision
                if (!(item instanceof Burger)) {
                    continue;
                }
                Burger burger = (Burger) item;
                JRadioButton btn = new JRadioButton(burger.getDescription() + " (" + getCurrentFormatter().format(burger.getPrice()) + ")");
                // Ok, this is just a little cheeky, but we're associating the
                // butger with the button for simplicity
                btn.putClientProperty("MenuItem", burger);
                bg.add(btn);
                // Add all the buttons share the same listener, because of polymorphism :D
                btn.addActionListener(actionListener);

                burgerPanel.add(btn, gbc);
            }
        }

        protected void buildCondiments() {
            condimentPanel.removeAll();
            condimentPanel.setLayout(new GridBagLayout());
            if (menu == null || order.getItem() == null) {
                return;
            }

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.weightx = 1;

            // Stick with me, this is a little more advanced, but provides
            // a really nice concept and ease of use
            // We could also make use of the Action API, but that might
            // pushing you just a little to far ;)
            ActionListener actionListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!(e.getSource() instanceof JCheckBox)) {
                        return;
                    }
                    JCheckBox checkBox = (JCheckBox) e.getSource();
                    Object obj = checkBox.getClientProperty("Condiment");
                    if (!(obj instanceof Condiment)) {
                        return;
                    }
                    Condiment condiment = (Condiment) obj;
                    if (checkBox.isSelected()) {
                        order.addCondiment(condiment);
                    } else {
                        order.removeCondiment(condiment);
                    }
                    orderDidChange();
                }
            };

            for (Condiment condiment : order.getItem().getCondiments()) {
                JCheckBox btn = new JCheckBox(condiment.getDescription() + " (" + getCurrentFormatter().format(condiment.getPrice()) + ")");
                // Ok, this is just a little cheeky, but we're associating the
                // butger with the button for simplicity
                btn.putClientProperty("Condiment", condiment);
                // Add all the buttons share the same listener, because of polymorphism :D
                btn.addActionListener(actionListener);
                condimentPanel.add(btn, gbc);
            }
        }

        public Menu getMenu() {
            return menu;
        }

        public void setMenu(Menu menu) {
            this.menu = menu;
            order = new DefaultOrder();
            buildBurgerMenu();
            orderDidChange();
        }

        protected void orderDidChange() {
            if (order == null) {
                totalLabel.setText("Amount: " + getCurrentFormatter().format(0));
                return;
            }

            // And now, some magic, how easy is it to get the expected
            // tally amount!!
            totalLabel.setText("Amount: " + getCurrentFormatter().format(order.getTally()));
        }

    }

    public interface Menu {
        public List<MainMenuItem> getMenuItems();
    }

    public interface MenuItem {
        public String getDescription();
        public double getPrice();
    }

    public interface Condiment extends MenuItem {
    }

    public interface MainMenuItem extends MenuItem {
        public List<Condiment> getCondiments();
    }

    public interface Burger extends MainMenuItem {
    }

    public interface Order {
        public MainMenuItem getItem();
        public void setItem(MainMenuItem item);
        public List<Condiment> getCondiments();
        public void addCondiment(Condiment condiment);
        public void removeCondiment(Condiment condiment);
        public double getTally();
    }

    public class DefaultOrder implements Order {

        private MainMenuItem item;
        private List<Condiment> condiments = new ArrayList<>();

        @Override
        public MainMenuItem getItem() {
            return item;
        }

        @Override
        public List<Condiment> getCondiments() {
            return Collections.unmodifiableList(condiments);
        }

        @Override
        public double getTally() {
            double tally = 0;
            if (item != null) {
                tally += item.getPrice();
            }
            for (Condiment condiment : condiments) {
                tally += condiment.getPrice();
            }
            return tally;
        }

        @Override
        public void setItem(MainMenuItem item) {
            this.item = item;
            // Oh look, we've established a "rule" that this model
            // applies, by itself, sweet
            condiments.clear();
        }

        @Override
        public void addCondiment(Condiment condiment) {
            // Bit pointless if the menu item is not set
            if (item == null) {
                return;
            }
            // Probably should check for duplicates
            condiments.add(condiment);
        }

        @Override
        public void removeCondiment(Condiment condiment) {
            // Bit pointless if the menu item is not set
            if (item == null) {
                return;
            }
            condiments.remove(condiment);
        }

    }

    public class DefaultMenu implements Menu {

        private List<MainMenuItem> menuItems = new ArrayList<>();

        public void add(MainMenuItem menuItem) {
            menuItems.add(menuItem);
        }

        @Override
        public List<MainMenuItem> getMenuItems() {
            return Collections.unmodifiableList(menuItems);
        }

    }

    public abstract class AbstractMenuItem implements MenuItem {

        private String description;
        private double price;

        public AbstractMenuItem(String description, double price) {
            this.description = description;
            this.price = price;
        }

        @Override
        public String getDescription() {
            return description;
        }

        @Override
        public double getPrice() {
            return price;
        }

    }

    public class DefaultCondiment extends AbstractMenuItem implements Condiment {

        public DefaultCondiment(String description, double price) {
            super(description, price);
        }

    }

    public class DefaultBurger extends AbstractMenuItem implements Burger {

        private List<Condiment> condiments;

        public DefaultBurger(String description, double price, List<Condiment> condiments) {
            super(description, price);
            // Protect ourselves from external modifications
            this.condiments = new ArrayList<>(condiments);
        }

        @Override
        public List<Condiment> getCondiments() {
            return Collections.unmodifiableList(condiments);
        }

    }
}
例如,当actionListener通过用户交互被触发时,它会做出一系列决策,如果一切顺利,这些决策将以更新的顺序结束,调用buildCondiments和orderDidChange方法,更新可用的调味品并更新UI的计数

这一切都是以抽象的方式完成的。actionListener不关心用户选择的MainMenuItem的类型,这不会更改其工作流,它只需要将该项应用于订单。同样徒劳的是,订单并不在意,因为它只需要价格信息来计算理货


因此,你可以添加新的菜单项和/或更改价格,一切都会继续工作好的,系好安全带,这将是一段旅程

模型的概念是您可以使用的最强大的概念之一。一个模型只是一个模型,是一种分离程序不同区域的方法。因此,一个模型,对数据进行建模,将其视为一个容器,然后视图将使用这些模型对数据进行格式化,以便用户分离关注点。模型还可以包含业务逻辑或根据其需求执行计算

允许您集中概念,这样您就不会重复自己或忘记做事。这也是一种改变程序部分工作方式的方法,也称为委派

起点 ,一些接口 好吧,那是很多废话,让我们开始吧。我更喜欢使用接口来描述事物,它提供了很多自由,因为您可以将不同的接口放在一起以满足不同的需求

菜单 好的,简单的概念,这是一个可以出售的物品清单

public interface Menu {
    public List<MainMenuItem> getMenuItems();
}
主菜单项 这些都是顶级的独立菜单项,在我们的例子中,可以有调味品:D

public interface MainMenuItem extends MenuItem {
    public List<Condiment> getCondiments();
}
汉堡 这只是你可以做的一些事情的一个演示,汉堡包并没有什么特别之处,但正如你将看到的,我们可以用这个概念做不同的事情

public interface Burger extends MainMenuItem {
}
顺序 最后是订单,我们点了什么,我们想要什么调味品

public interface Order {
    public MainMenuItem getItem();
    public void setItem(MainMenuItem item);
    public List<Condiment> getCondiments();
    public void addCondiment(Condiment condiment);
    public void removeCondiment(Condiment condiment);
    public double getTally();
}
好的,试着不要太沉迷于此,但是看看这里抽象的用法。AbstractMenuItem封装了所有MenuItem实现都将需要的许多常见功能,所以我们不需要重复自己,亲爱的

其中一些实现已经在做出决策或应用规则。例如,当主菜单项发生更改时,DefaultOrder将清除调味品。它还可以确保所使用的调味品实际上可用于该项目

还要注意的是,tally方法不是存储的属性,但每次调用它时都会重新计算。这是一个设计决策,要将其变成一个存储属性并不难,因此每次更改MenuMenuItem、添加和/或删除调味品时,该属性都会更新,但我感觉很懒。但是你可以看到这些东西是如何改变的,它会影响这些模型的所有用户,sweet:D

好吧,但这究竟是如何回答这个问题的呢?嗯,实际上有点

所以,这个想法是,你从一张空白订单开始。用户选择一个主要项目,即汉堡,您将其设置为订单,然后更新UI作为响应。UI要求订单计算理货,并将其呈现给用户

此外,同样的概念也适用于调味品。每次用户添加或删除调味品时,订单都会更新,用户也会更新UI

好吧,但也许,举个例子更容易理解

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                List<Condiment> condiments = new ArrayList<>(3);
                condiments.add(new DefaultCondiment("Ketchup", 0.5));
                condiments.add(new DefaultCondiment("Mustard", 0.5));
                condiments.add(new DefaultCondiment("Pickles", 0.5));

                DefaultMenu menu = new DefaultMenu();
                menu.add(new DefaultBurger("Beef", 4.0, condiments));
                menu.add(new DefaultBurger("Chicken", 3.5, condiments));
                menu.add(new DefaultBurger("Veggie", 4.0, condiments));

                MenuPane menuPane = new MenuPane();
                menuPane.setMenu(menu);

                frame.add(menuPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MenuPane extends JPanel {

        private Menu menu;
        private Order order;
        private List<Condiment> selectedCondiments = new ArrayList<>();

        private JPanel burgerPanel;
        private JPanel condimentPanel;
        private JPanel totalPanel;

        private JLabel totalLabel;
        private JButton clearButton;
        private JButton payButton;

        private NumberFormat currencyFormatter;

        public MenuPane() {
            setLayout(new GridBagLayout());

            order = new DefaultOrder();

            burgerPanel = new JPanel();
            burgerPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
            condimentPanel = new JPanel();
            condimentPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
            totalPanel = makeTotalPanel();
            totalPanel.setBorder(new EmptyBorder(8, 8, 8, 8));

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.weightx = 1;
            gbc.weighty = 0.5;

            add(burgerPanel, gbc);

            gbc.gridy++;
            add(condimentPanel, gbc);

            gbc.gridy++;
            gbc.weighty = 0;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(totalPanel, gbc);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 200);
        }

        protected NumberFormat getCurrentFormatter() {
            if (currencyFormatter != null) {
                return currencyFormatter;
            }
            currencyFormatter = NumberFormat.getCurrencyInstance();
            currencyFormatter.setMinimumFractionDigits(2);
            return currencyFormatter;
        }

        protected JPanel makeTotalPanel() {
            JPanel totalPanel = new JPanel(new GridBagLayout());
            totalLabel = new JLabel();
            clearButton = new JButton("CLR");
            payButton = new JButton("PAY");

            clearButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    order = new DefaultOrder();
                    buildCondiments();
                    orderDidChange();
                }
            });

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.gridx = 0;
            gbc.gridy = 0;
            totalPanel.add(totalLabel, gbc);

            gbc.weightx = 0;
            gbc.gridx++;
            totalPanel.add(clearButton, gbc);
            gbc.gridx++;
            totalPanel.add(payButton, gbc);
            return totalPanel;
        }

        protected void buildBurgerMenu() {
            burgerPanel.removeAll();
            burgerPanel.setLayout(new GridBagLayout());
            if (menu == null) {
                return;
            }

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.weightx = 1;

            ButtonGroup bg = new ButtonGroup();

            // Stick with me, this is a little more advanced, but provides
            // a really nice concept and ease of use
            // We could also make use of the Action API, but that might
            // pushing you just a little to far ;)
            ActionListener actionListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!(e.getSource() instanceof JComponent)) {
                        return;
                    }
                    JComponent comp = (JComponent) e.getSource();
                    Object obj = comp.getClientProperty("MenuItem");
                    // I'm putting this here to demonstrate part of the concept
                    // of polymorphism - techncially, we don't have to care
                    // of it's a burger or some other type of menu item,
                    // only that this is going to represent the "main" item
                    if (!(obj instanceof MainMenuItem)) {
                        return;
                    }
                    MainMenuItem item = (MainMenuItem) obj;
                    order.setItem(item);

                    buildCondiments();
                    orderDidChange();
                }
            };

            System.out.println(menu.getMenuItems().size());
            for (MenuItem item : menu.getMenuItems()) {
                // Only interested in burgers
                // Could have the Menu do this, but that's a design
                // decision
                if (!(item instanceof Burger)) {
                    continue;
                }
                Burger burger = (Burger) item;
                JRadioButton btn = new JRadioButton(burger.getDescription() + " (" + getCurrentFormatter().format(burger.getPrice()) + ")");
                // Ok, this is just a little cheeky, but we're associating the
                // butger with the button for simplicity
                btn.putClientProperty("MenuItem", burger);
                bg.add(btn);
                // Add all the buttons share the same listener, because of polymorphism :D
                btn.addActionListener(actionListener);

                burgerPanel.add(btn, gbc);
            }
        }

        protected void buildCondiments() {
            condimentPanel.removeAll();
            condimentPanel.setLayout(new GridBagLayout());
            if (menu == null || order.getItem() == null) {
                return;
            }

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.weightx = 1;

            // Stick with me, this is a little more advanced, but provides
            // a really nice concept and ease of use
            // We could also make use of the Action API, but that might
            // pushing you just a little to far ;)
            ActionListener actionListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!(e.getSource() instanceof JCheckBox)) {
                        return;
                    }
                    JCheckBox checkBox = (JCheckBox) e.getSource();
                    Object obj = checkBox.getClientProperty("Condiment");
                    if (!(obj instanceof Condiment)) {
                        return;
                    }
                    Condiment condiment = (Condiment) obj;
                    if (checkBox.isSelected()) {
                        order.addCondiment(condiment);
                    } else {
                        order.removeCondiment(condiment);
                    }
                    orderDidChange();
                }
            };

            for (Condiment condiment : order.getItem().getCondiments()) {
                JCheckBox btn = new JCheckBox(condiment.getDescription() + " (" + getCurrentFormatter().format(condiment.getPrice()) + ")");
                // Ok, this is just a little cheeky, but we're associating the
                // butger with the button for simplicity
                btn.putClientProperty("Condiment", condiment);
                // Add all the buttons share the same listener, because of polymorphism :D
                btn.addActionListener(actionListener);
                condimentPanel.add(btn, gbc);
            }
        }

        public Menu getMenu() {
            return menu;
        }

        public void setMenu(Menu menu) {
            this.menu = menu;
            order = new DefaultOrder();
            buildBurgerMenu();
            orderDidChange();
        }

        protected void orderDidChange() {
            if (order == null) {
                totalLabel.setText("Amount: " + getCurrentFormatter().format(0));
                return;
            }

            // And now, some magic, how easy is it to get the expected
            // tally amount!!
            totalLabel.setText("Amount: " + getCurrentFormatter().format(order.getTally()));
        }

    }

    public interface Menu {
        public List<MainMenuItem> getMenuItems();
    }

    public interface MenuItem {
        public String getDescription();
        public double getPrice();
    }

    public interface Condiment extends MenuItem {
    }

    public interface MainMenuItem extends MenuItem {
        public List<Condiment> getCondiments();
    }

    public interface Burger extends MainMenuItem {
    }

    public interface Order {
        public MainMenuItem getItem();
        public void setItem(MainMenuItem item);
        public List<Condiment> getCondiments();
        public void addCondiment(Condiment condiment);
        public void removeCondiment(Condiment condiment);
        public double getTally();
    }

    public class DefaultOrder implements Order {

        private MainMenuItem item;
        private List<Condiment> condiments = new ArrayList<>();

        @Override
        public MainMenuItem getItem() {
            return item;
        }

        @Override
        public List<Condiment> getCondiments() {
            return Collections.unmodifiableList(condiments);
        }

        @Override
        public double getTally() {
            double tally = 0;
            if (item != null) {
                tally += item.getPrice();
            }
            for (Condiment condiment : condiments) {
                tally += condiment.getPrice();
            }
            return tally;
        }

        @Override
        public void setItem(MainMenuItem item) {
            this.item = item;
            // Oh look, we've established a "rule" that this model
            // applies, by itself, sweet
            condiments.clear();
        }

        @Override
        public void addCondiment(Condiment condiment) {
            // Bit pointless if the menu item is not set
            if (item == null) {
                return;
            }
            // Probably should check for duplicates
            condiments.add(condiment);
        }

        @Override
        public void removeCondiment(Condiment condiment) {
            // Bit pointless if the menu item is not set
            if (item == null) {
                return;
            }
            condiments.remove(condiment);
        }

    }

    public class DefaultMenu implements Menu {

        private List<MainMenuItem> menuItems = new ArrayList<>();

        public void add(MainMenuItem menuItem) {
            menuItems.add(menuItem);
        }

        @Override
        public List<MainMenuItem> getMenuItems() {
            return Collections.unmodifiableList(menuItems);
        }

    }

    public abstract class AbstractMenuItem implements MenuItem {

        private String description;
        private double price;

        public AbstractMenuItem(String description, double price) {
            this.description = description;
            this.price = price;
        }

        @Override
        public String getDescription() {
            return description;
        }

        @Override
        public double getPrice() {
            return price;
        }

    }

    public class DefaultCondiment extends AbstractMenuItem implements Condiment {

        public DefaultCondiment(String description, double price) {
            super(description, price);
        }

    }

    public class DefaultBurger extends AbstractMenuItem implements Burger {

        private List<Condiment> condiments;

        public DefaultBurger(String description, double price, List<Condiment> condiments) {
            super(description, price);
            // Protect ourselves from external modifications
            this.condiments = new ArrayList<>(condiments);
        }

        @Override
        public List<Condiment> getCondiments() {
            return Collections.unmodifiableList(condiments);
        }

    }
}
例如,当actionListener通过用户交互被触发时,它会做出一系列决策,如果一切顺利,这些决策将以更新的顺序结束,调用buildCondiments和orderDidChange方法,更新可用的调味品并更新UI的计数

这一切都是以抽象的方式完成的。actionListener不关心用户选择的MainMenuItem的类型,这不会更改其工作流,它只需要将该项应用于订单。同样徒劳的是,订单并不在意,因为它只需要价格信息来计算理货


因此,你可以添加新的菜单项和/或更改价格,一切都会继续工作好的,简单的概念你真正想了解的是模型的概念,你可以保存东西,它可以执行计算并生成其他东西,这些东西可以被你的代码的其他部分使用-这是一个非常常见的概念,是模型-视图-控制器概念的关键好的,简单的概念你真正想了解的是模型的概念,您可以在其中保存内容,它可以执行计算并生成代码其他部分可以使用的其他内容-这是一个非常常见的概念,是模型-视图-控制器概念的关键