设计模式-工厂模式

简单工厂模式

大家都很喜欢吃面条,面条有很多种类,有泡面、兰州拉面、莆田卤面等。

抽象出一个面条接口类(产品接口类):

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.");  
    }  
} 

抽象工厂优点
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理.

抽象工厂缺点
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的

适用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。

说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。

假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点

总结

  • 无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。
  • 在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式
  • 所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值