预计阅读时间:7--9 min
情景引入:
「男朋友女朋友男女朋友生男女」
女朋友:我不想吃你买的苹果,不想吃你买的菠萝,更不想吃苹果。不想吃,不想吃,统统不想吃!!!
男朋友:不想吃,不想吃就给我滚。(豪横)
女朋友转身...
·
·
·
(此时床上躺着一个“女朋友”)
图片来自网络,侵删
女朋友:人家想吃芒果,想吃柠檬嘛。
男朋友:what?
(努力回忆:简单工厂模式中,你要啥,给我一个名字,让工厂给送啥。现在又多了俩,那我是不是再去修改下,添加上这两个就可以了)
(但这不是办法啊,如果以后还要需求咋办...)
男朋友:来,告诉我,明天会不会又说 不想要苹果了,并让它从此消失。然后还要一堆乱七八糟的,啊。
女朋友:那不一定......
啊。
看来啊,这简单工厂模式,只满足工厂类负责创建的对象比较少的情况,否则,工厂类中的业务逻辑会太过复杂;但是,它非常适用于客户端只知道传入给工厂的参数的情况,对象如何创建的不需要关心。
面对上述「男朋友·女朋友」如此变幻的需求,先用工厂模式来代替看一下。
在此之前,先加一道小菜,里氏代换原则。
定义:
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
俗语化:
所有引用基类(父类)的地方必须能透明地使用其子类的对象。
也就是 subtype(子类型)和subclass(子类)的不同。严格来讲,o1 和 o2 满足 subtype 才可以实现 substituted,而subtype 不易判断, subclass 更易判断,现实中就先用 subclass 代替来判断。
在软件中,能够使用基类对象,那么一定能够使用其子类对象。
工厂模式定义:
Define an interface for creating anobject, but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.
读不懂看下面:
定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。
工厂方法模式让一个类的实例化延迟到其子类。
它是一种类创建型模式。
角色:
Product:抽象产品
ConcreteProduct:具体产品
Factory:抽象工厂
ConcreteFactory:具体工厂
类图:
代码:
产品接口,具体产品非常简单,产品接口中声明一个consume方法,具体产品中实现 consume 方法。比如打印一句“concreteProductXXX 已送到”。
工厂类负责创建对应工厂。
代码语言:javascript复制// 假装新建了 产品接口类,具体产品类
···done···
//工厂接口
public interface Factory{
public Product create();
}
// 具体工厂
public class ConcreteFactory1 implements Factory{
public Product create(){
return new ConcreteProduct();
}}
// 客户端调用
···
Factory factory;
Product product;
factory = new ConcreteFactory1();
product = factory.create();
product.consume();
···
本例中的类图:
本例中的代码:
产品接口 Fruit,只声明一个方法即可:
代码语言:javascript复制package com.sample.factorypattern.product;
public interface Fruit {
public void consume();
}
具体产品,AppleFruit类:
代码语言:javascript复制package com.sample.factorypattern.product;
public class AppleFruit implements Fruit{
@Override
public void consume() {
System.out.println("红富士苹果送到了");
}
}
MangoFruit 类:
代码语言:javascript复制package com.sample.factorypattern.product;
public class MangoFruit implements Fruit {
@Override
public void consume() {
System.out.println("黄黄的芒果来了");
}
}
工厂接口 Factory,同样只声明一个方法:
代码语言:javascript复制package com.sample.factorypattern.factory;
import com.sample.factorypattern.product.Fruit;
public interface Factory {
public Fruit create();
}
具体工厂,AppleFactory 类:
代码语言:javascript复制package com.sample.factorypattern.factory;
import com.sample.factorypattern.product.AppleFruit;
import com.sample.factorypattern.product.Fruit;
public class AppleFactory implements Factory {
@Override
public Fruit create() {
return new AppleFruit();
}
}
芒果工厂,MangoFactory 类:
代码语言:javascript复制package com.sample.factorypattern.factory;
import com.sample.factorypattern.product.Fruit;
import com.sample.factorypattern.product.MangoFruit;
public class MangoFactory implements Factory {
@Override
public Fruit create() {
return new MangoFruit();
}
}
客户端调用,工厂对象,产品(水果)对象,反复使用,还节省了内存:
代码语言:javascript复制package com.sample.factorypattern;
import com.sample.factorypattern.factory.AppleFactory;
import com.sample.factorypattern.factory.Factory;
import com.sample.factorypattern.factory.MangoFactory;
import com.sample.factorypattern.product.Fruit;
public class Client {
public static void main(String[] args){
Factory factory;
Fruit fruit;
//想吃苹果
factory = new AppleFactory();
fruit = factory.create();
fruit.consume();
//想吃芒果
factory = new MangoFactory();
fruit = factory.create();
fruit.consume();
}
}
运行效果:
项目结构:
工厂模式优点:
·工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节
·能够让工厂自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部
·在系统中加入新产品时,完全符合开闭原则
缺点:
·类的个数将成对增加
·增加了系统的抽象性和理解难度
适用环境:
·客户端不知道它所需要的对象的类(客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体产品对象由具体工厂类创建)
·抽象工厂类通过其子类来指定创建哪个对象
总感觉这个模式,duangduangduang 多了好多类,活也没怎么干明白。别慌,还有它的升级版,抽象工厂模式,等我,下一篇就来了。
感谢
感谢阅读,感谢陪伴。没关注的记得关注一下。
表情包资源来自网络,侵删。
原创不易