`
rq2_79
  • 浏览: 240528 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java设计模式之抽象工厂模式篇

阅读更多

 

抽象工厂模式是一种比工厂模式抽象程度更高的模式。简而言之,抽象工厂类和工厂类的原理相同,只不过工厂类返回的是普通类的实例;而抽象工厂类返回的是一个工厂类的实例。

抽象工厂类最经典的应用支持多个GUI界面,例如Java的程序同时支持Windows、Motif和Macintosh的界面(这种技术被称为界面类型,look-and-feel)。开发人员可以通过抽象工厂获得某种界面对应的GUI工厂类,通过GUI工厂类开发人员可以对界面上的组件(例如按钮、文本框等)进行操作。从Java 1.2 开始,Java在系统层提供了实现了抽象工厂模式的界面类型。当开发人员在程序中确定界面类型后,就可以通过界面类型获得界面上组件的实例。例如在下面的这段代码中,程序获得操作系统的类型,并根据操作系统设定程序的界面类型:

String laf = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(laf);
}
catch (UnsupportedLookAndFeelException exc)
{
System.err.println("UnsupportedL&F: " + laf);
}
catch (Exception exc)
{
System.err.println("Error loading " + laf);
}

例子

让我们通过一个简单的例子来看一看抽象工厂模式是如何在应用层被使用的。假设你才买了一套住宅,屋顶有一个花园,而你需要设计一下花园的布局。花园右侧有一个花台,边上需要种一排植物,中心需要种主体植物。根据风格的不同,花园可以被设计为典雅型、使用型和懒人型。

首先我们需要一个Garden类作为基类,通过该类中可以获得花园中种植的植物:

// Garden.java
public abstract class Garden
{
   public abstract Plant getShade(); // 花台中的植物
   public abstract Plant getCenter(); // 中间的植物
   public abstract Plant getBorder(); // 边上的植物
}

然后我们需要实现Plant类,在该类中保存植物的名称。

// Plant.java
public class Plant
{
String name;
  public Plant(String pname)
  {
    name = pname;     
  }        
  public String getName()
  {
     return name;
  }
}

在实际的应用中,每种类型的花园对应的植物应该从数据库中查找。在这里为了方便,将每种植物的类型花园对应的植物类型直接写在程序中:

// ElegantGarden.java (典雅型)
public class ElegantGarden extends Garden
{
   public Plant getShade()
   {
      return new Plant("郁金香");
   }
 public Plant getCenter()
 {
    return new Plant("榕树");
 }
 public Plant getBorder()
 {
    return new Plant("兰草");
 }
}
// PracticalGarden.java (实用型)
public class PracticalGarden extends Garden
{
   public Plant getShade()
   {
      return new Plant("葡萄");
   }
 public Plant getCenter()
 {
    return new Plant("石榴");
 }
 public Plant getBorder()
 {
    return new Plant("丝瓜");
 }
}
// LasyGarden.java(懒人型)
public class LasyGarden extends Garden
{
   public Plant getShade()
   {
      return new Plant("月季");
   }
 public Plant getCenter()
 {
    return new Plant("茶花");
 }
 public Plant getBorder()
 {
    return new Plant("竹");
 }
}

现在我们有了一组Garden的子类,每个子类都实现了同样的方法:getShade(),getCenter()和getBorder()。现在可以通过给抽象工厂类传递特殊的参数获得某一中类型的花园的实例:

// GardenMaker.java
public class GardenMaker 
{
 // 抽象工厂类  
   private Garden gd;   
   public Garden getGarden(String gtype)
   {
      gd = new ElegantGarden();   //缺省情况
      if(gtype.equals("实用型"))
           gd = new PracticalGarden();
      if(gtype.equals("懒人型"))
           gd = new LasyGarden();
      return gd;
   }   
}

运行程序后显示下面的窗口:

在界面中包含了两个部分:左边选择花园的类型。当用户选择了其中一种类型后,程序通过抽象工厂类MakeGarden获得实际的Garden类的实例。

public void itemStateChanged(ItemEvent e)
   {
      Checkbox ck = (Checkbox)e.getSource();
      garden = new GardenMaker().getGarden(ck.getLabel());
      shadePlant=""; centerPlant=""; borderPlant = "";
      gardenPlot.repaint();
   }

当用户按下"中间"、"墙边"或"花台"的按钮时,程序返回Plant对象,然后通过GardenPanel类将Plant对象的名称显示在界面上:

//----------------------------------
public void actionPerformed(ActionEvent e)
{
      Object obj = e.getSource();
      if(obj == Center)
         setCenter();
      if(obj == Border)
         setBorder();
      if(obj == Shade)
         setShade();
      if(obj == Quit)
      System.exit(0);
   }
   //----------------------------------
   private void setCenter()
   {
      if(garden != null) centerPlant = garden.getCenter().getName();
      gardenPlot.repaint();
   }
   private void setBorder()
   {
      if(garden != null) borderPlant = garden.getBorder().getName();
      gardenPlot.repaint();
   }
   private void setShade()
   {
      if(garden != null) shadePlant = garden.getShade().getName();
      gardenPlot.repaint();
   }

程序中其他类的软代码如下所示:

// Gardener.java
import java.awt.*;
import java.awt.event.*;
public class Gardener extends Frame
   implements ActionListener, ItemListener
{
   private Checkbox Elegant, Practical, LasyBoy;
   private Button Center, Border, Shade, Quit;
   private Garden garden = null;
   private GardenPanel gardenPlot;
   private String borderPlant = "", centerPlant = "", shadePlant = "";
   public Gardener()
   {
      super("屋顶花园规划");
      setGUI();
   }
   //----------------------------------
   private void setGUI()
   {
      setBackground(Color.lightGray);
      setLayout(new GridLayout(1,2));
      Panel left = new Panel();
      add(left);
      Panel right= new Panel();
      add(right);
      left.setLayout(new GridLayout(4, 1));
      left.add(new Label("花园类型"));
      CheckboxGroup grp= new CheckboxGroup();
      Elegant = new Checkbox("典雅型", grp, false);
      Practical = new Checkbox("实用型", grp, false);
      LasyBoy = new Checkbox("懒人型", grp, false);
      left.add(Elegant);
      left.add(Practical);
      left.add(LasyBoy);
      Elegant.addItemListener(this);
      LasyBoy.addItemListener(this);
      Practical.addItemListener(this);
      right.setLayout(new GridLayout(2,1));
      gardenPlot = new GardenPanel();
      gardenPlot.setBackground(Color.white);
      Panel botRight = new Panel();
      right.add(gardenPlot);
      right.add(botRight);
      Center = new Button("中间");
      Border =  new Button("墙边");
      Shade = new Button("花台");
      Quit = new Button("退出");
      botRight.add(Center);
      Center.addActionListener(this);
      botRight.add(Border);
      Border.addActionListener(this);
      botRight.add(Shade);
      Shade.addActionListener(this);
      botRight.add(Quit);
      Quit.addActionListener(this);
      setBounds(200,200, 400,300);
      setVisible(true);
    }
   //----------------------------------
   public void actionPerformed(ActionEvent e)
   {
      Object obj = e.getSource();
      if(obj == Center)
         setCenter();
      if(obj == Border)
         setBorder();
      if(obj == Shade)
         setShade();
      if(obj == Quit)
         System.exit(0);
   }
   //----------------------------------
   private void setCenter()
   {
      if(garden != null) centerPlant = garden.getCenter().getName();
      gardenPlot.repaint();
   }
   private void setBorder()
   {
      if(garden != null) borderPlant = garden.getBorder().getName();
      gardenPlot.repaint();
   }
   private void setShade()
   {
      if(garden != null) shadePlant = garden.getShade().getName();
      gardenPlot.repaint();
   }
   //----------------------------------
   public void itemStateChanged(ItemEvent e)
   {
      Checkbox ck = (Checkbox)e.getSource();
      garden = new GardenMaker().getGarden(ck.getLabel());
      shadePlant=""; centerPlant=""; borderPlant = "";
      gardenPlot.repaint();
   }
   //----------------------------------
   static public void main(String argv[])
   {
      new Gardener();
   }
//--------------------------------
class GardenPanel extends Panel
 {
   public void paint (Graphics g)
   {
      Dimension sz=getSize();
      g.setColor(Color.lightGray);
      g.fillArc( 0, 0, 80, 80,0, 360);
      g.setColor(Color.black);
      g.drawRect(0,0, sz.width-1, sz.height-1);
      g.drawString(centerPlant, 100, 50);
      g.drawString( borderPlant, 75, 120);
      g.drawString(shadePlant, 10, 40);
   }
 }
}     // Gardener.java

小结

使用抽象工厂模式的一个主要原因是由于它能够将实现类和它们的生成过程完全分割开来。实现类被隐藏在工厂类中,调用者不必知道实现类的任何信息。由于这种特性,开发人员也很容易在一组实现类中进行替换。虽然抽象工厂中的子类继承了同一个基类,但是它们也可以拥有与其他子类不同的方法。例如在ElegantGarden类中,我们可以加上花架和假山的属性以及获得这两个属性的方法;而在其他的花园类中则不需要包含这两个属性。当然在程序中需要判断当前的实例是否支持这些特殊的方法,解决的方案有两种:一种是将包含特殊方法在内的所有的方法都定义在基类中,只有支持特殊方法的类才实现这些特殊方法;另一种方案是在抽象类中判断实现类的类型:

分享到:
评论
1 楼 rq2_79 2009-02-27  
工厂模式在项目中是常常用到的,有人说只有大项目才会用到,小项目是体会不出来.其实使用设计模式与项目的大小没有实质性的联系.设计模式是经验的总结而不是衡量项目大小的标准.

以开发项目的DAO层为例,在项目中客户的需求是常常变动的,临时更换数据库的需求也是常常发生的,那我们要如何解决跨数据库的功能,这里就要使用到抽象工厂模式了.工厂模式常常用于创建多系列化的对象(如Orale系列,MySql系列)

1.首先定义相关接口(与平常的做法没什么区别)

Java代码
// 角色表DAO接口
interface IroleDao {
void insert();

void update();
}
// 用户表DAO接口
interface IuserDao {
void find();

void delete();
}

// 角色表DAO接口
interface IroleDao {
void insert();

void update();
}
// 用户表DAO接口
interface IuserDao {
void find();

void delete();
} 2.不同的数据库有不同的SQL语句所以实现时必须分数据库来实现

Java代码
// 用户表Oralce数据库DAO
class OracleuserDao implements IuserDao {
public void delete() {
System.out.println("Oralce 删除用户表数据");
}

public void find() {
System.out.println("Oralce 查询用户表数据");
}
}

// 用户表MySql数据库DAO
class MySqluserDao implements IuserDao {
public void delete() {
System.out.println("MySql 删除用户数据");
}

public void find() {
System.out.println("MySql 查询用户数据");
}
}
// 角色表Oracle数据库DAO
class OracleroleDao implements IroleDao {
public void insert() {
System.out.println("Oralce 对角色表插入数据");
}

public void update() {
System.out.println("Oracle 对角色表更新数据");
}
}

// 角色表MySql数据库DAO
class MySqlroleDAO implements IroleDao {
public void insert() {
System.out.println("MySql 对角色表插入数据");
}

public void update() {
System.out.println("Mysql 对角色表更新数据");
}
}

// 用户表Oralce数据库DAO
class OracleuserDao implements IuserDao {
public void delete() {
System.out.println("Oralce 删除用户表数据");
}

public void find() {
System.out.println("Oralce 查询用户表数据");
}
}

// 用户表MySql数据库DAO
class MySqluserDao implements IuserDao {
public void delete() {
System.out.println("MySql 删除用户数据");
}

public void find() {
System.out.println("MySql 查询用户数据");
}
}
// 角色表Oracle数据库DAO
class OracleroleDao implements IroleDao {
public void insert() {
System.out.println("Oralce 对角色表插入数据");
}

public void update() {
System.out.println("Oracle 对角色表更新数据");
}
}

// 角色表MySql数据库DAO
class MySqlroleDAO implements IroleDao {
public void insert() {
System.out.println("MySql 对角色表插入数据");
}

public void update() {
System.out.println("Mysql 对角色表更新数据");
}
}
这里增加了一套DAO的实现 (与平时有所不同,如果有10个数据库就要加上10种不同的实现,比较麻烦呀)

3.定义DAO工厂接口与实现(利用java反射机制生产出你需要的DAO如:userDAO,roleDao)

Java代码
// DAO工厂
abstract class DaoFactory {
public static DaoFactory getInstance(String classname) {
DaoFactory dao = null;
try {
dao = (DaoFactory) Class.forName(classname).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return dao;
}

abstract IuserDao getuserdao();

abstract IroleDao getroledao();
}

// Oralce工厂
class OracleFactory extends DaoFactory {
public IroleDao getroledao() {
return new OracleroleDao();
}
public IuserDao getuserdao() {
return new OracleuserDao();
}
}

// MySql工厂
class MysqlFactory extends DaoFactory {
public IroleDao getroledao() {
return new MySqlroleDAO();
}
public IuserDao getuserdao() {
return new MySqluserDao();
}
}

// DAO工厂
abstract class DaoFactory {
public static DaoFactory getInstance(String classname) {
DaoFactory dao = null;
try {
dao = (DaoFactory) Class.forName(classname).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return dao;
}

abstract IuserDao getuserdao();

abstract IroleDao getroledao();
}

// Oralce工厂
class OracleFactory extends DaoFactory {
public IroleDao getroledao() {
return new OracleroleDao();
}
public IuserDao getuserdao() {
return new OracleuserDao();
}
}

// MySql工厂
class MysqlFactory extends DaoFactory {
public IroleDao getroledao() {
return new MySqlroleDAO();
}
public IuserDao getuserdao() {
return new MySqluserDao();
}
}

4. 定义配置文件

Java代码
class Config {
// Oralce
static final String ORALCE = "org.abc.OracleFactory";

static final String MYSQL = "org.abc.MysqlFactory";
}

class Config {
// Oralce
static final String ORALCE = "org.abc.OracleFactory";

static final String MYSQL = "org.abc.MysqlFactory";
}

配置文件可以定义到XML中去(好处:修改配置项之后不需要对JAVA文件进行编译.)

5.测试你的输出的DAO

Java代码
public class Dao {
public static void main(String[] args) {
DaoFactory.getInstance(Config.ORALCE).getroledao().insert();
DaoFactory.getInstance(Config.MYSQL).getroledao().insert();
}

}

public class Dao {
public static void main(String[] args) {
DaoFactory.getInstance(Config.ORALCE).getroledao().insert();
DaoFactory.getInstance(Config.MYSQL).getroledao().insert();
}

}

总结

使用条件:一系列接口有一系列的实现
如上IuserDao、IroleDao等一系列的接口,他们可以有一系列的实现(Oracle方式、MySql方式)

OracleuserDao、OracleroleDao、MySqluserDao、MySqlroleDAO
组成元素(以上面例子)
一系列接口:IuserDao、IroleDao
一系列实现:Oracle系列、MySql系列
系列工厂类:Oracle系列工厂类、MySql系列工厂类(必须继承抽象工厂类)
抽象工厂类:DaoFactory

相关推荐

    java设计模式之抽象工厂模式

    java设计模式之抽象工厂模式实例,希望对大家有所帮助。

    JAVA设计模式之抽象工厂

    **JAVA设计模式之抽象工厂** 在软件工程中,设计模式是一种通用的解决方案,用来解决在特定上下文中反复出现的问题。抽象工厂(Abstract Factory)模式是其中一种创建型设计模式,它提供一个创建对象的接口,但允许...

    JAVA设计模式之抽象工厂模式

    在"JAVA设计模式之抽象工厂模式"的示例中,可能会包含这些角色的实现以及如何在实际场景中应用抽象工厂模式的解释和示例代码。这个压缩包可能包含了详细的设计和实现,帮助学习者深入理解抽象工厂模式的工作原理及其...

    Java设计模式之抽象工厂模式

    总结来说,Java设计模式之抽象工厂模式是一种用来创建一系列相关对象的设计模式,它通过提供抽象工厂接口来隔离具体产品的创建,使系统具备更好的扩展性和封装性。在实际开发中,我们可以根据需求选择使用抽象工厂...

    java设计模式-抽象工厂模式

    总的来说,抽象工厂模式在Java中是一种非常实用的设计模式,它可以帮助我们封装产品的创建过程,降低系统间的耦合度,同时提供了更好的可扩展性,使得添加新的产品族或者产品变得更加容易。在处理具有多种变体的复杂...

    Java设计模式-抽象工厂

    **Java设计模式——抽象工厂** 在软件工程中,设计模式是一种在特定场景下解决常见问题的模板或蓝图。抽象工厂模式是设计模式中的一种结构型模式,它提供了一个创建对象族的接口,但允许子类决定实例化哪一个类。这...

    Java设计模式之抽象工厂模式.zip

    通过阅读《Java设计模式之抽象工厂模式.pdf》这份文档,你可以更深入地理解抽象工厂模式的原理、实现方式以及如何在Java项目中应用这一模式。文档中可能涵盖了模式的优缺点、实例分析、与其他设计模式的比较等内容,...

    JAVA设计模式之抽象工厂模式案例

    抽象工厂模式是软件设计模式中的一种,属于创建型模式,它提供了一种创建对象组族的接口,而无需指定其具体类。这种模式的关键在于抽象工厂,它定义了一组产品对象的接口,并且允许子类根据不同的实现来生产一系列...

    Java设计模式之抽象工厂模式.docx

    抽象工厂模式是设计模式中的一种,属于创建型模式,它为创建一组相关或相互依赖的对象提供了一个统一的接口,使得客户端无需关注这些对象的具体实现细节,仅需与抽象工厂交互即可。这种模式遵循开放封闭原则(OCP)...

    Java 工厂模式 抽象工厂 工厂方法模式

    本文将深入探讨Java中的工厂模式,包括基本的工厂模式、抽象工厂模式以及工厂方法模式。 **工厂模式**:工厂模式的核心思想是提供一个创建对象的接口,但让实现这个接口的类来决定实例化哪一个类。这样,客户端无需...

    java常用设计模式-抽象工厂模式

    java常用设计模式-抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它通过定义一个创建对象的接口来创建对象,但将具体实现的决定留给子类来决定。在抽象工厂模式中,接口是负责创建...

    探索Java设计模式:工厂模式与抽象工厂模式的比较

    工厂模式和抽象工厂模式是两种常用的创建型设计模式,它们在Java中有着广泛的应用。本文将详细探讨这两种模式的区别,并提供代码示例来加深理解。 工厂模式和抽象工厂模式都是创建型设计模式,它们提供了代码解耦和...

    工厂模式:简单工厂模式、工厂方法模式、抽象工厂模式

    工厂模式分为三种主要类型:简单工厂模式、工厂方法模式和抽象工厂模式。 1. **简单工厂模式** 简单工厂模式是最简单的工厂模式实现,它提供一个静态方法或者类来创建对象,这个类通常被称为“工厂”。用户只需要...

    Java设计模式之抽象工厂模式.pdf

    在Java设计中,抽象工厂模式通常用于处理多个相关产品对象的创建。例如,我们可能有一个系统需要创建不同类型的植物(Plant)和水果(Fruit),每种类型都有其特定的实现,如PlantA和PlantB,FruitA和FruitB。这些...

    JAVA设计模式研究之抽象工厂模式

    【JAVA设计模式研究之抽象工厂模式】 设计模式是软件工程中的重要概念,它们代表了在特定情境下解决常见问题的最佳实践。面向对象编程中的设计模式,如抽象工厂模式,是提高代码可重用性和可维护性的关键。抽象工厂...

    Java设计模式教程 - Java设计模式 - 抽象工厂模式

    抽象工厂模式是Java设计模式中的一种创建型模式,它提供了创建对象族的接口,而具体的对象族由子类决定。这种模式的主要目的是隔离接口与实现,使得客户端代码在更换产品族时无需修改,增强了软件的可扩展性和可维护...

Global site tag (gtag.js) - Google Analytics