在上一篇博客中我们使用了工厂模式来设计一个网上车辆交易系统,在那个例子中只有汽车这一种单一类型的商品。那么,如果有多种类型的商品,还能用工厂方法模式吗?举个例子,现在有个网上服装买卖系统,有三种服装---鞋、套装和衬衫,其中又分为男鞋女鞋、男套装和女套装、男衬衫和女衬衫,即如下商品:
按照上节中说到的工厂方法模式,应该这样设计,使用三个工厂来创建三个对象:
这样做也能实现,但是工厂类有点多吧,而且在客户端中将会有很多的条件语句,有没有什么更好的办法呢?我们在分析看看,商品有三种,性别对应着男、女,那么我们为什么不从另一个角度来思考问题,不再建立生产shoes、shirt和suit的工厂,而是建立生产男人的衣服工厂ManCloseFactory和生产女人衣服的工厂WomanCLoseFactory。如下设计:
类图设计好了,现在只需要两个工厂就能搞定了,那么编代码试试吧:
shirt接口:
public interface Shirt {
public String getInfo();
}
suit接口:
public interface Suit {
public String getInfo();
}
shoes接口:
public interface Shoes {
public String getInfo();
}
ManShirt类:
public class ManShirt implements Shirt {
@Override
public String getInfo() {
// TODO Auto-generated method stub
String info = "男 衬衫";
return info;
}
}
WomanShirt类:
public class WomanShirt implements Shirt {
@Override
public String getInfo() {
// TODO Auto-generated method stub
String info = "女 衬衫";
return info;
}
}
ManSuit类:
public class ManSuit implements Suit {
@Override
public String getInfo() {
// TODO Auto-generated method stub
String info = "男 套装";
return info;
}
}
WomanSuit类:
public class WomanSuit implements Suit {
@Override
public String getInfo() {
// TODO Auto-generated method stub
String info = "女 套装";
return info;
}
}
ManShoes类:
public class ManShoes implements Shoes {
@Override
public String getInfo() {
// TODO Auto-generated method stub
String info = "男 鞋";
return info;
}
}
WomanShoes类:
public class WomanShoes implements Shoes {
@Override
public String getInfo() {
// TODO Auto-generated method stub
String info = "女 鞋";
return info;
}
}
工厂类的基类:
public abstract class CloseFactory {
public static final String MAN = "男";
public static final String WOMAN = "女";
public abstract Shoes getShoes();
public abstract Suit getSuit();
public abstract Shirt getShirt();
public static CloseFactory getCloseFactory(String Sex){
CloseFactory CF = null;
if(Sex.equals(MAN)){
CF = new ManCloseFactory();
}else if(Sex.equals(WOMAN)){
CF = new WomanCloseFactory();
}
return CF;
}
}
男服生产工厂,ManCloseFactory:
public class ManCloseFactory extends CloseFactory {
@Override
public Shoes getShoes() {
// TODO Auto-generated method stub
return new ManShoes();
}
@Override
public Suit getSuit() {
// TODO Auto-generated method stub
return new ManSuit();
}
@Override
public Shirt getShirt() {
// TODO Auto-generated method stub
return new ManShirt();
}
}
女服生产工厂,WomanCloseFactory:
public class WomanCloseFactory extends CloseFactory {
@Override
public Shoes getShoes() {
// TODO Auto-generated method stub
return new WomanShoes();
}
@Override
public Suit getSuit() {
// TODO Auto-generated method stub
return new WomanSuit();
}
@Override
public Shirt getShirt() {
// TODO Auto-generated method stub
return new WomanShirt();
}
}
客户端:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class clientGUI extends JFrame implements ActionListener{
private String SHOES = "鞋";
private String SHIRT = "衬衫";
private String SUIT = "套装";
private String MAN = "男";
private String WOMAN = "女";
private JLabel labelShowSex;
private JLabel labelShowType;
private JTextArea textShowInfo;
private JComboBox ChoiceSex;
private JComboBox ChoiceType;
private JButton BtnOK;
private JButton BtnExit;
private JPanel panelNorth;
private JPanel panelCenter;
private JPanel panelSouth;
public void initComponents(){
labelShowSex = new JLabel("请选择性别:");
labelShowType = new JLabel("请选择服饰:");
textShowInfo = new JTextArea();
textShowInfo = new JTextArea();
textShowInfo.setColumns(20);
textShowInfo.setRows(100);
textShowInfo.setBackground(Color.PINK);
ChoiceSex = new JComboBox();
ChoiceSex.addItem(MAN);
ChoiceSex.addItem(WOMAN);
ChoiceType = new JComboBox();
ChoiceType.addItem(SHOES);
ChoiceType.addItem(SHIRT);
ChoiceType.addItem(SUIT);
BtnOK = new JButton("OK");
BtnOK.addActionListener(this);
BtnExit = new JButton("EXIT");
BtnExit.addActionListener(this);
panelNorth = new JPanel();
panelCenter = new JPanel();
panelSouth = new JPanel();
}
public void panelAddComponenets(){
panelNorth.add(labelShowSex);
panelNorth.add(ChoiceSex);
panelNorth.add(labelShowType);
panelNorth.add(ChoiceType);
panelCenter.add(textShowInfo);
panelSouth.add(BtnOK);
panelSouth.add(BtnExit);
}
public void mainFrameAddPanel(){
this.add("North", panelNorth);
this.add("Center", panelCenter);
this.add("South", panelSouth);
}
public void mianFramSet(){
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation((d.width - this.getSize().width)/2, (d.height - this.getSize().height)/2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(300, 200);
this.setVisible(true);
}
public clientGUI(){
initComponents();
panelAddComponenets();
mainFrameAddPanel();
mianFramSet();
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == BtnOK){
String Sex = ChoiceSex.getSelectedItem().toString();
String Type = ChoiceType.getSelectedItem().toString();
CloseFactory cf = CloseFactory.getCloseFactory(Sex);//根据性别调用相应的工厂
if(Type.equals(SHIRT)){//根据类型生产相应的产品
Shirt s = cf.getShirt();
String info = s.getInfo();
textShowInfo.setText(info);
}else if(Type.equals(SHOES)){
Shoes s = cf.getShoes();
String info = s.getInfo();
textShowInfo.setText(info);
}else if(Type.equals(SUIT)){
Suit s = cf.getSuit();
String info = s.getInfo();
textShowInfo.setText(info);
}
}
if(e.getSource() == BtnExit){
System.exit(0);
}
}
}
测试:
public class mian {
public static void main(String[] args) {
// TODO Auto-generated method stub
clientGUI cGUI = new clientGUI();
}
}
这样设计是不是好多了!!!
总结一下,抽象工厂模式应用在产品类别不唯一的情况,而工厂模式应用在产品类别单一的情况。再画一下抽象工厂模式的设计图:
上节中说到,工厂方法符合开闭原则,但是抽象工厂方法只是部分的符合开闭原则,举个例子: