代码示例:https://github.com/elfc/patterns
分类
创建型
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
动机
考虑一个支持多种主题的用户界面工具包,例如:Planet和Mars。不同视感风格为诸如按钮、菜单和窗口等用户界面“窗口组件”定义不同的外观和行为。为保证视感风格标准间的可移植性,一个应用不应该为一个特定的视感外观硬编码它的窗口组件。在整个应用中实例化特定视感风格的窗口组件类将使得以后很难改变视感风格。
为解决这一问题我们可以定义一个抽象的ThemeFactory类,这个类声明了一个用来创建每一类基本窗口组件的接口。每一类窗口组件都有一个抽象类,而具体子类则实现了窗口组件的特定视感风格。对于每一个抽象窗口组件类,ThemeFactory接口都有一个返回新窗口组件对象的操作。客户调用这些操作以获得窗口组件实例,但客户并不知道他们正在使用的是哪些具体类。这样客户就不依赖一般的视感风格。
每一种视感标准都对应于一个具体的ThemeFactory子类。每一子类实现那些用于创建合适视感风格的窗口组件的操作。
例如:PlanetThemeFactory的createButton操作实例化并返回一个Planet按钮,而相应的MarsThemeFactory操作返回一个Mars按钮。客户仅通过ThemeFactory接口创建窗口组件,他们并不知道那些类实现了特定视感风格的窗口组件。也就是,客户仅与抽象类定义的接口交互,而不是用特定的具体类的接口。
ThemeFactory也增强了具体窗口组件类之间的依赖关系。一个Planet的按钮应该与Planet菜单等一起使用,这一约束条件作为使用PlanetThemeFactory的结果被自动加上。
适用性
一个系统要独立于它的产品的创建、组合时。
一个系统要由多个产品系列中的一个来配置时。
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
结构
参与者
- AbstractFactory(ThemeFactoryFactory)
-- 声明一个创建抽象产品对象的操作接口
- ConcreteFactory(PlanetThemeFactory、MarsThemeFactory)
-- 实现创建具体产品对象的操作
- AbstractProduct(Button、Menu)
-- 定义一个将被相应的具体工厂创建的产品对象
-- 实现AbstractProduct接口
- Client
-- 仅使用由AbstractFactory和AbstractProduct类声明的接口
代码示例
/**
* 菜单接口
* AbstractProductB
* @author chunyuliu
*/
public interface Menu {
/**
* 风格
* @return
*/
String style();
/**
* 菜单布局
* @return
*/
String layout();
}
/**
*
* 地球主题菜单
* ProductB1
*
* @author chunyuliu
*/
public class PlanetMenu implements Menu {
@Override
public String style() {
String msg = "我是地球主题菜单";
System.out.println(msg);
return msg;
}
@Override
public String layout() {
String msg = "地球主题菜单布局";
System.out.println(msg);
return msg;
}
}
/**
*
* 火星主题菜单
* ProductB2
*
* @author chunyuliu
*/
public class MarsMenu implements Menu {
@Override
public String style() {
String msg = "我是火星主题菜单";
System.out.println(msg);
return msg;
}
@Override
public String layout() {
String msg = "火星主题菜单布局";
System.out.println(msg);
return msg;
}
}
/**
* 按钮接口
* AbstractProductA
* @author chunyuliu
*/
public interface Button {
/**
* 风格
* @return
*/
String style();
/**
* 点击
* @return
*/
String click();
}
/**
* 地球主题按钮
* ProductA1
*
* @author chunyuliu
*/
public class PlanetButton implements Button {
@Override
public String style() {
String msg = "我是地球主题按钮";
System.out.println(msg);
return msg;
}
@Override
public String click() {
String msg = "点击我会显示地球";
System.out.println(msg);
return msg;
}
}
/**
* 火星主题按钮
* ProductA2
*
* @author chunyuliu
*/
public class MarsButton implements Button {
@Override
public String style() {
String msg = "我是火星主题按钮";
System.out.println(msg);
return msg;
}
@Override
public String click() {
String msg = "点击我会显示火星";
System.out.println(msg);
return msg;
}
}
/**
* 一个创建抽象产品对象的操作接口
* AbstractFactory
*
* @author chunyuliu
*/
public interface ThemeFactory {
/**
* 新建按钮
* CreateProductA
* @return
*/
Button createButton();
/**
* 新建菜单
* CrateProductB
* @return
*/
Menu createMenu();
}
/**
*
* 实现创建具体产品对象操作
* ConcreteFactory1
*
* @author chunyuliu
*/
public class PlanetThemeFactory implements ThemeFactory {
@Override
public Button createButton() {
return new PlanetButton();
}
@Override
public Menu createMenu() {
return new PlanetMenu();
}
}
/**
*
* 实现创建具体产品对象操作
* ConcreteFactory2
*
* @author chunyuliu
*/
public class MarsThemeFactory implements ThemeFactory {
@Override
public Button createButton() {
return new MarsButton();
}
@Override
public Menu createMenu() {
return new MarsMenu();
}
}
/**
* @author chunyuliu
*/
public class AbstractFactoryTest {
@Test
public void planetFactoryTest() {
// 地球主题工厂
ThemeFactory themeFactory = new PlanetThemeFactory();
// 按钮
Button button = themeFactory.createButton();
button.style();
button.click();
// 菜单
Menu menu = themeFactory.createMenu();
menu.style();
menu.layout();
}
@Test
public void marsFactoryTest() {
// 火星主题工厂
ThemeFactory themeFactory = new MarsThemeFactory();
// 按钮
Button button = themeFactory.createButton();
button.style();
button.click();
// 菜单
Menu menu = themeFactory.createMenu();
menu.style();
menu.layout();
}
}
效果
它分离了具体的类
它使得易于交换产品系列
它有利于产品的一致性
难以支持新种类的产品