创建型设计模式(1):工厂模式


工厂模式对将调用的方法或者通过new创建类对象的过程进行封装。就好像使用数据库中间件的过程,无需关心底层的实现,只需要将用户名和密码上传即可。

工厂模式的优点如下,

  • 一个调用者想创建某个对象只需要知道名称即可
  • 屏蔽具体的行为过程,调用者只需掌握接口方法,减轻负担
  • 拓展性高,如果想增加一个类进入工厂,只需要拓展一个工厂类即可

从简单工厂引入,深入到工厂模式

简单工厂分类

工厂模式分为3种,

  1. 普通简单工厂模式
  2. 多方法简单工厂
  3. 静态方法简单工厂

3种模式从上到下逐渐抽象,并更具一般性。以信息、快递和邮件的发送为例进行说明。

1.普通简单工厂

image

  1. 创建接口
    三者共有的接口,
public interface Sender {
	public void Send();
}
  1. 创建发送信息、邮件和快递的实现类
public class EmailSender implements Sender{
	@Override
	public void send() {
		System.out.println("发送邮件");
	}
}

public class SmsSender implements Sender{
	@Override
	public void send() {
		System.out.println("发送短信");
	}
}

public class ExpressSender implements Sender{
	@Override
	public void send() {
		System.out.println("发送快递");
	}
}
  1. 创建普通简单工厂
public class SendFactory{
	public Sender produce(String type) {
		if (type == null)
			return null;
		else if ("email".equalsIgnoreCase(type))
			return new EmailSender();
		else if ("sms".equalsIgnoreCase(type))
			return new SmsSender();
		else if ("express".equalsIgnoreCase(type))
			return new ExpressSender();
		else
			return null;	
	}
}
  1. 调用普通简单工厂
public class Main {
    public static void main(String[] args) {
        SendFactory sendFactory = new SendFactory();
        Sender senderSms = sendFactory.produce("sms");
        senderSms.Send(); // 发送短信

        Sender senderEmail = sendFactory.produce("email");
        senderEmail.Send(); // 发送邮件

        Sender senderExpress = sendFactory.produce("express");
        senderExpress.Send(); // 发送快递
    }
}
  1. 小结
    普通简单工厂在使用时,如果参数type传递错误就无法正确创建对象。

2.多方法简单工厂

image
依旧使用普通简单工厂类中的3个Sender接口实现类。

  1. 基于普通简单工厂进行修改
    只需要对SendFactory类进行修改即可,
public class SendFactory {
    public Sender produceSms(){
        return new SmsSender();
    }

    public Sender produceEmail(){
        return new EmailSender();
    }

    public Sender produceExpress() {
        return new ExpressSender();
    }
}
  1. 测试多方法简单工厂
public class Main {

    public static void main(String[] args) {
        SendFactory sendFactory = new SendFactory();
        Sender senderEmail = sendFactory.produceEmail();
        senderEmail.Send(); // 发送邮件

        Sender senderSms = sendFactory.produceSms();
        senderSms.Send(); // 发送短信

        Sender senderExpress = sendFactory.produceExpress();
        senderExpress.Send(); // 发送快递
    }
}
  1. 小结
    普通工厂模式和多方法工厂模式均存在一个弊端,即需要频繁实例化工厂类

3.静态方法简单工厂

一般情况下会将多方法简单工厂中的创建实例的方法设置为静态,从而避免频发实例化工厂类。
image

  1. 测试静态方法简单工厂
public class Main {
    public static void main(String[] args) {
        Sender senderEmail = SendFactory.produceEmail();
        senderEmail.Send(); // 发送邮件

        Sender senderSms = SendFactory.produceSms();
        senderSms.Send(); // 发送短信

        Sender senderExpress = SendFactory.produceExpress();
        senderExpress.Send(); // 发送快递
    }
}
  1. 小结
    静态方法简单工厂仍有明显的弊端,即工厂类中定义了所有市里的创建逻辑,违背高内聚的责任分配原则和闭包规则

工厂方法模式

1.模式说明

工厂方法模式是简单工厂的延伸,将原先存在于一个工厂类中的逻辑抽调出来,创建一个接口和多个工厂类
image
这种方式在拓展工厂功能时有很好的表现,无需修改之前的代码。

2.开发实例

基于简单工厂中创建的3个Sender接口实现类进行开发。

  1. 统一工厂类的接口行为
public interface Provider {
    public Sender produce();
}
  1. 实现3个工厂类并进行行为约束
public class EmailSendFactory implements Provider{
	@Override
	public Sender produce() {
		return new EmailSender();
	}
}

public class SmsSendFactory implements Provider{
	@Override
	public Sender produce() {
		return new SmsSender();
	}
}

public class ExpressSendFactory implements Provider{
	@Override
	public Sender produce() {
		return new ExpressSender();
	}
}
  1. 测试工厂模式
public class Main {
    public static void main(String[] args) {
        Provider providerSms = new SmsSendFactory();
        Sender senderSms = providerSms.produce();
        senderSms.Send(); // 发送短信

        Provider providerEmail = new EmailSendFactory();
        Sender senderEmail = providerEmail.produce();
        senderEmail.Send(); // 发送邮件

        Provider providerExpress = new ExpressSendFactory();
        Sender senderExpress = providerExpress.produce();
        senderExpress.Send(); // 发送快递
    }
}
  1. 小结
    上方的代码具体的好处在于拓展性。
    1) 不要把焦点放在new 上面,这里的好处并不是 newnew的问题。
    2)真正的好处是,多方法简单工厂的最大弊端是:如果需要增加一个新的Sender接口实现类,就不得不去修改工厂类SendFactory的代码。
    工厂类作为一个基础类尽量不要做改动。试想,如果每当要加一个实现类就改动工厂,工厂类不断膨胀,后期很难维护,要符合开闭原则。
    如果用工厂方法就不一样了,对工厂进行接口化,并提供各Sender接口实现类对应的工厂类。如果要新增实现类,就再扩展一个新的工厂,不会对接口进行改变。虽然调用过程中代码量多了,但是在实际业务中会极大的方便后期维护。这样是低耦合的,并且符合开闭原则。

抽象工厂模式

是最具抽象性和一般性的形态。可以像客户端提供一个接口,客户端无需指定产品的情况下,创建多个对象。

以电脑生产为例,比较工厂方法模式和抽象工厂模式,

模式实现
工厂方法模式需要主板工厂、CPU工厂、显卡工厂等
抽象工厂模式只有一个PC工厂,该工厂中再包含主板、显卡和CPU工厂

简言之,工厂方法模式的工厂类针对同一类产品;抽象工厂模式的工厂类针对多种类的产品。

1.模式特点

  1. 系统中有多个产品族,每个具体工厂负责创建同一族但是不同种类(产品等级)的产品。产品族产品等级的概念如下,
    image
  2. 系统一次只能消费某一产品族的产品
  3. 当系统需要新增一个产品族时,只需要增加新的工厂类即可,无需修改源代码;但是如果需要产品族中增加一个新种类的产品时,则所有的工厂类都需要修改

抽象工厂模式中的抽象工厂类的职责就是定义每个工厂要实现的功能,即定义多个产品族的产品的创建。这里,同一产品族下有多个产品时,对应的抽象工厂就会有多个抽象方法用来提供创建这些产品的接口。

2.组成角色

抽象工厂中的四种角色,

角色说明
抽象工厂提供创建产品的接口,包含多个创建产品的方法,即包含多个类似的方法
具体工厂实现抽象工厂定义的接口,完成具体产品的创建
抽象产品一般有多少抽象产品,抽象工厂中就有多少个创建产品的方法
具体产品抽象产品的实现类

image

3.开发实例

  1. 定义抽象工厂接口
public interface Factory {
    Television newTelevision();
    Refrigerator newRefrigerator();
}
  1. 定义抽象产品接口
public interface Television {
    void dosomething();
}

public interface Refrigerator {
    void dosomething();
}
  1. 实现具体工厂类
public class TCLFactory implements Factory {
    @Override
    public Television newTelevision() {
        return new TCLTelevision();
    }

    @Override
    public Refrigerator newRefrigerator() {
        return new TCLRefrigerator();
    }
}


public class MeiDFactory implements Factory {
    @Override
    public Television newTelevision() {
        return new MeiDTelevision();
    }

    @Override
    public Refrigerator newRefrigerator() {
        return new MeiDRefrigerator();
    }
}
  1. 实现具体产品类
public class TCLTelevision implements Television {
    @Override
    public void dosomething() {
        System.out.println("我是TCL电视机,我可以看电视");
    }
}

public class MeiDTelevision implements Television {
    @Override
    public void dosomething() {
        System.out.println("我是美的电视机,我可以看电视");
    }
}

public class TCLRefrigerator implements Refrigerator {
    @Override
    public void dosomething() {
        System.out.println("我是TCL冰箱,我可以洗衣服");
    }
}

public class MeiDRefrigerator implements Refrigerator {
    @Override
    public void dosomething() {
        System.out.println("我是美的冰箱,我可以洗衣服");
    }
}
  1. 测试
public class Main {
    public static void main(String[] args) {
        Factory factory = new TCLFactory();
        Television television = factory.newTelevision();
        Refrigerator refrigerator = factory.newRefrigerator();
        television.dosomething(); // 我是TCL电视机,我可以看电视
        refrigerator.dosomething(); // 我是TCL冰箱,我可以洗衣服

        factory = new MeiDFactory();
        television = factory.newTelevision();
        refrigerator = factory.newRefrigerator();
        television.dosomething(); // 我是美的电视机,我可以看电视
        refrigerator.dosomething(); // 我是美的冰箱,我可以洗衣服
    }
}

4.良好拓展性

  1. 新增产品族
    假设某天新增海尔的电视机和冰箱,
    image
    体现了开闭原则,对修改关闭,对拓展开放。产品族拓展不需要修改源代码即可实现功能拓展。
  2. 新增产品等级
    假设某天TCL和美的上新电风扇,
    image
    当需要增加一个新的产品时,所有的工厂类都需要进行修改,修改产品等级时,不满足开闭原则。所以,这也是抽象工厂的一个弊端
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值