工厂模式
作者:互联网
概述
最近在翻看公司源码时发现很多框架在进行配置的时候都会用到XxFactory
的类进行配置,尽管学生时候没有怎么学过设计模式,但看到 Factory 还是下意识的反应这大概是工厂模式,大学没好好学习的坑看来得工作以后填了,所以打算学习一下设计模式这块的内容,从工厂模式开始
简介
了解到工厂模式其实是一个大的概念,如果细分又可以分成:简单工厂、工厂方法、抽象工厂三种模式。这三种模式大概可以立即为由简单工厂演变到工厂方法,再由工厂方法演变到抽象工厂,三者的关系属于由易到难,所以下面的内容也遵循这个思路
简单工厂模式
这种模式是由一个工厂对象决定创建出哪一种产品类的实例。实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例
作用是:将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦
主要角色
- 工厂:负责实现创建所有实例的内部逻辑,并提供一个外界调用的方法,创建所需的产品对象
- 抽象产品:负责描述产品的公共接口
- 具体产品:描述生产的具体产品
举个简单易懂的例子:
“假设”有一台饮料机(工厂,用于创建所需产品对象——饮料)
可以调出各种口味的饮料(抽象产品,意义上的饮料)
有三个按钮(参数,比如熟知的肯德基饮料机上的按钮对应百事可乐、美年达、七喜)对应这三种饮料(具体产品,是意义上的饮料的子类)
这时候你可以根据点击按钮来选择你喜欢的饮料(使用者不需要考虑饮料是怎么出来的,只要用杯子接住就好了)
简单的实例
/*
* 描述抽象产品的公共接口
* */
public interface ColdDrink {
public void someDrink();
}
------------------------------
/*
* 具体产品:可乐
* */
public class Coke implements ColdDrink {
@Override
public void someDrink() {
System.out.println("一杯可乐");
}
}
------------------------------
/*
* 具体产品:雪碧
* */
public class Sprite implements ColdDrink {
@Override
public void someDrink() {
System.out.println("一杯雪碧");
}
}
------------------------------
/*
* 工厂
* 负责实现创建所有实例的内部逻辑,并提供一个外界调用的方法,创建所需的产品对象
* */
public class Factory {
/*
* 供外界调用的方法,可以想象成饮料机上不同的按钮
* */
public static ColdDrink product(String name) {
switch (name) {
case "coke":
return new Coke();
case "sprite":
return new Sprite();
default:
return null;
}
}
}
------------------------------
/*
* 测试类
* */
public class simpleFactoryTest {
public static void main(String[] args) {
// 创建具体工厂
Factory coldDrinkFactory = new Factory();
// 根据不同按钮生产饮料(根据不同参数生产产品实例)
coldDrinkFactory.product("coke").someDrink();
}
}
总结
根据以上代码可以总结出:一个抽象产品类,可以派生出多个具体产品类。一个具体工厂类,通过往此工厂的static方法中传入不同参数,产出不同的具体产品类实例
优点:将创建和使用分开,不必关心类对象如何创建,实现了解耦
缺点:违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂
开闭原则:软件实体 (类、模块、函数等等) 应该是可以被扩展的,但是不可被修改
工厂方法模式
这个是我们熟知的那个工厂模式。通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分
主要角色
- 抽象工厂:描述具体工厂的公共接口
- 具体工厂:描述具体工厂,创建产品的实例,供外界调用
- 抽象产品:负责描述产品的公共接口
- 具体产品:描述生产的具体产品
举个简单的例子:
“假设”有各类的饮料机(抽象工厂)
可以调出各种的饮料(抽象产品)
但是一类饮料机(具体工厂)
只能生产一种饮料(具体产品)
所以如果你需要喝可乐,就需要买可乐饮料机。
简单的实例
商品们
/*
* 描述抽象产品的公共接口
* */
public interface ColdDrink {
public void someDrink();
}
------------------------------
/*
* 具体产品:可乐
* */
public class Coke implements ColdDrink {
@Override
public void someDrink() {
System.out.println("一杯可乐");
}
}
------------------------------
/*
* 具体产品:雪碧
* */
public class Sprite implements ColdDrink {
@Override
public void someDrink() {
System.out.println("一杯雪碧");
}
}
工厂们
/*
* 抽象工厂
* */
public interface Factory {
// 生产产品
public ColdDrink getColdDrink();
}
------------------------------
/*
* 具体工厂,负责可乐的生产
* */
public class FactoryA implements Factory {
@Override
public ColdDrink getColdDrink() {
return new Coke();
}
}
------------------------------
/*
* 具体工厂,负责雪碧的生产
* */
public class FactoryB implements Factory {
@Override
public ColdDrink getColdDrink() {
return new Sprite();
}
}
测试类
public class MyTest {
public static void main(String[] args) {
Factory factoryA = new FactoryA();
Factory factoryB = new FactoryB();
factoryA.getColdDrink().someDrink();
factoryB.getColdDrink().someDrink();
}
}
总结
根据代码可以总结出这个模式的一般规律:一个抽象产品类,可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例
其实通过观察实例就能发现它相较于简单工厂模式的优点在于:
- 符合开-闭原则:新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
- 符合单一职责原则:每个具体工厂类只负责创建对应的产品
缺点也显而易见:
- 因为每个工厂只能生产一种产品,所以增加了系统的复杂度:类的个数(尤其是工厂子类的个数)将成对增加
- 增加了系统的抽象性和理解难度(这个其实倒还好,只是相较于简单工厂模式确实难理解了一些)
- 一个具体工厂只能创建一种具体产品(也就是导致系统复杂度的罪魁祸首)
抽象工厂模式
抽象工厂模式是由工厂方法模式演变而来的。工厂方法模式只考虑生产同等级的产品,比如计算机学院只培养计算机学生,电视厂只生产电视。但现实生活中许多工厂都是综合性工厂,例如海尔的工厂既能生产电视又能生产空调
这里不得不说一下什么叫产品等级,什么叫产品族
主要角色
- 抽象工厂:描述具体工厂的公共接口
- 具体工厂:描述具体工厂,创建产品的实例,供外界调用
- 抽象产品族:描述抽象产品的公共接口
- 抽象产品:描述具体产品的公共接口
- 具体产品:具体产品
一个简单的实例
抽象产品族(电器)
// 包含一个介绍电器的方法
public interface ElectricalAppliances {
public void introduce();
}
抽象产品:空调和电视
// 抽象产品:空调
public abstract class Aircondition implements ElectricalAppliances {
@Override
public abstract void introduce();
}
------------------------------
// 抽象产品:电视
public abstract class Television implements ElectricalAppliances {
@Override
public abstract void introduce();
}
具体产品:海尔空调、海信空调、海尔电视、海信电视
public class HaierAircondition extends Aircondition {
@Override
public void introduce() {
System.out.println("海尔牌空调");
}
}
------------------------------
public class HisenseAircondition extends Aircondition {
@Override
public void introduce() {
System.out.println("海信牌空调");
}
}
------------------------------
public class HairTelevision extends Television {
@Override
public void introduce() {
System.out.println("海尔牌电视");
}
}
------------------------------
public class HisenseTelevision extends Television {
@Override
public void introduce() {
System.out.println("海信牌电视");
}
}
超级工厂,用于创建海尔工厂和海信工厂
public abstract class SuperFactrory {
public abstract ElectricalAppliances getAircondition();
public abstract ElectricalAppliances getTelevision();
}
海尔工厂(只能制造海尔的电器)和海信工厂(只能生产海信的电器)
// 海尔工厂
public class HairFactory extends SuperFactrory {
@Override
public ElectricalAppliances getAircondition() {
return new HairAircondition();
}
@Override
public ElectricalAppliances getTelevision() {
return new HairTelevision();
}
}
------------------------------
// 海信工厂
public class HisenseFactory extends SuperFactrory {
@Override
public ElectricalAppliances getAircondition() {
return new HisenseAircondition();
}
@Override
public ElectricalAppliances getTelevision() {
return new HisenseTelevision();
}
}
测试类
public class MyTest {
public static void main(String[] args) {
SuperFactrory hairFactory = new HairFactory();
SuperFactrory hisenseFactory = new HisenseFactory();
hairFactory.getAircondition().introduce();
hisenseFactory.getTelevision().introduce();
}
}
大致结构图是这样的
总结
抽象工厂模式很好的解决了工厂方法模式下一个工厂只能生产一种产品的问题,但是也带来了一些问题:增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类
标签:模式,public,抽象,产品,具体,工厂,class 来源: https://www.cnblogs.com/colee51666/p/16457678.html