简单工厂模式
大家都很喜欢吃面条,面条有很多种类,有泡面、兰州拉面、莆田卤面等。
抽象出一个面条接口类(产品接口类):
public interface Noodles {
void desc();
}
泡面实现类(具体产品实现类):
public class PaoNoodlesImpl implements Noodles{
@Override
public void desc() {
System.out.println("简单工厂模式:程序员最爱吃的泡面");
}
}
兰州拉面实现类(具体产品实现类):
public class LzNoodlesImpl implements Noodles {
@Override
public void desc() {
System.out.println("简单工厂模式:兰州拉面,闻名遐迩");
}
}
莆田卤面实现类(具体产品实现类):
public class PutianNoodlesImpl implements Noodles {
@Override
public void desc() {
System.out.println("简单工厂模式:莆田卤面,我的最爱");
}
}
定义一个简单工厂类:
public class SimpleNoodlesFactory {
public static final int TYPE_LZ = 1;//兰州拉面
public static final int TYPE_PM = 2;//泡面
public static final int TYPE_PT = 3;//莆田卤面
public static Noodles createNoodles(int type) {
switch (type) {
case TYPE_LZ:
return new LzNoodlesImpl();
case TYPE_PM:
return new PaoNoodlesImpl();
case TYPE_PT:
default:
return new PutianNoodlesImpl();
}
}
}
测试类:
@Controller
@RequestMapping("/factory")
public class FactoryTestController {
@RequestMapping("/simple.json")
@ResponseBody
public String simple() {
Noodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_PT);
noodles.desc();
return "simple factory success";
}
}
类图
特点
- 这个工厂类是一个具体的类,非接口、抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回
- 一个工厂负责创建所有实例
- create()方法通常是静态的,所以也称之为静态工厂
缺点
- 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
- 不同的产品需要不同额外参数的时候,不支持
工厂方法模式
模式描述
为外部提供一个用于创建对象的接口(工厂接口),而不是具体的工厂类了,让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例
模式作用
可以一定程度上解耦,消费者和产品实现类隔离开,只依赖产品接口(抽象产品),产品实现类如何改动与消费者完全无关。
可以一定程度增加扩展性,若增加一个产品实现,只需要实现产品接口,修改工厂创建产品的方法,消费者可以无感知。
可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少的代码量就可以完成很多工作。
另外,抽象工厂才是实际意义的工厂模式,工厂方法只是抽象工厂的一个比较常见的情况
适用场景
消费者不关心它所要创建对象的类(产品类)的时候。
消费者知道它所要创建对象的类(产品类),但不关心如何创建的时候。
例如:hibernate里通过sessionFactory创建session等等。
模式要素
涉及如下四种角色
- 抽象工厂角色:是工厂方法模式的核心,与应用程序无关,任何在该模式中创建的对象的工厂类必须实现这个接口(也可以是抽象类)
- 具体工厂角色:实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象,允许有多个工厂实现类
- 抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口
- 具体产品角色:实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应
图解说明
具体的工厂A和B是完全独立的,且各对应一个产品接口,与抽象工厂Abstract Factory是不同的(下面会介绍)
产品类图
工厂类图
代码实现
产品接口类:
public interface Message {
Map<String, Object> getMessageParam();
void setMessageParam(Map<String, Object> messageParam);
/**
* 发送通知
*/
void sendMessage();
}
产品抽象类:
public abstract class AbstractMessage implements Message {
/**
* 生产产品所需要的原材料
*/
private Map<String, Object> messageParam;
@Override
public Map<String, Object> getMessageParam() {
return this.messageParam;
}
@Override
public void setMessageParam(Map<String, Object> messageParam) {
this.messageParam = messageParam;
}
}
产品实现类(邮件):
public class EmailMessageImpl extends AbstractMessage{
@Override
public void sendMessage() {
System.out.println("工厂方法模式:邮件发送,携带参数[" + getMessageParam().get("email") + "]");
}
}
产品实现类(短信):
public class SmsMessageImpl extends AbstractMessage{
@Override
public void sendMessage() {
System.out.println("工厂方法模式:短信发送,携带参数[" + getMessageParam().get("sms") + "]");
}
}
工厂接口类:
public interface MessageFactory {
Message createMessage(String messageType);
}
工厂实现类(这里只列出一个实现类,其实可以定义很多实现类):
public class MyMessageFactoryImpl implements MessageFactory {
@Override
public Message createMessage(String messageType) {
// 这里的方式是:消费者知道自己想要什么产品
// 若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数
Map<String, Object> messageParam = new HashMap<String, Object>();
Message message = null;
if ("EMAIL".equals(messageType)) {
messageParam.put("email", "email is 12345");
message = new EmailMessageImpl();
} else if ("SMS".equals(messageType)) {
messageParam.put("sms", "sms is 110");
message = new SmsMessageImpl();
} else {
messageParam.put("sms", "sms is 110");
message = new SmsMessageImpl();
}
message.setMessageParam(messageParam);
return message;
}
}
测试类:
@Controller
@RequestMapping("/factory")
public class FactoryTestController {
/**
* 工厂方法模式
* @return
*/
@RequestMapping("/method.json")
@ResponseBody
public String method() {
MessageFactory messageFactory = new MyMessageFactoryImpl();
//邮件通知
Message message = messageFactory.createMessage("EMAIL");
message.sendMessage();
//短信通知
message = messageFactory.createMessage("SMS");
message.sendMessage();
return "method factory success";
}
}
抽象工厂模式
定义
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
图解
抽象工厂模式和工厂方法模式区别
- 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象
- 工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类
- 在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构
举一个汽车的例子:
- 在上面的类图中,两厢车和三厢车称为两个不同的等级结构
- 2.0排量两厢车和2.4排量两厢车属于同一个等级结构,2.0排量三厢车和2.4排量三厢车属于另一个等级结构
- 2.0排量两厢车和2.0排量三厢车属于同一个产品族,2.4排量两厢车和2.4排量三厢车属于另一个产品族
如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。
在本例中,如果一个工厂模式提供2.0排量两厢车和2.4排量两厢车,那么他属于工厂方法模式;如果一个工厂模式是提供2.4排量两厢车和2.4排量三厢车两个产品,那么这个工厂模式就是抽象工厂模式,因为他提供的产品是分属两个不同的等级结构。
当然,如果一个工厂提供全部四种车型的产品,因为产品分属两个等级结构,他当然也属于抽象工厂模式了。
抽象工厂模式代码
/**
* 抽象工厂类
**/
public abstract class AbstractFactory {
public abstract Flyable createFlyable();
public abstract Moveable createMoveable();
public abstract Writeable createWriteable();
}
/**
* 抽象工厂实现类
**/
public class Factory1 extends AbstractFactory {
@Override
public Flyable createFlyable() {
return new Aircraft();
}
@Override
public Moveable createMoveable() {
return new Car();
}
@Override
public Writeable createWriteable() {
return new Pen();
}
}
/**
* 抽象产品Flyable类
**/
public interface Flyable {
public void fly(int height);
}
/**
* Flyable产品实现类
**/
public class Aircraft implements Flyable {
@Override
public void fly(int height) {
System.out.println("我是一架客运机,我目前的飞行高度为:" + height + "千米。");
}
}
/**
* 测试
**/
public class FactoryTest {
public static void main(String[] args) {
AbstractFactory factory = new Factory1();
Flyable flyable = factory.createFlyable();
flyable.fly(1589);
Moveable moveable = factory.createMoveable();
moveable.run(87.6);
Writeable writeable = factory.createWriteable();
writeable.write("Hello World.");
}
}
抽象工厂优点
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理.
抽象工厂缺点
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的
适用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。
说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。
假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点
总结
- 无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。
- 在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式
- 所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。