设计模式专栏第二弹,抽象工厂
抽象工厂
字面意思:一个xx工厂,可以是水果工厂,化肥工厂,江南皮革厂...跑题了,那么为什么叫做抽象
呢,后续带你慢慢揭开抽象
的面纱。
先上定义:抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类。
问题抛出
假设你正在开发宠物商店项目。可能里面牵扯很多种动物,比如:狗,猫...,狗呢又有很多分类,比如:黑的,白的,牧羊犬... 这时候你需要单独的生成每种类型动物对应的对象,这样才能保证其正确性。同时呢,我们也不想添加新产品时修改已有代码,要不然以后每次添加新类型的动物,岂不是都要改动原有的代码。
解决方法:
首先, 抽象工厂模式建议为系列中的每件产品明确声明接口 (例如狗、 猫)。 然后, 确保所有产品变体都继承这些接口。 例如, 所有类型的狗都实现
狗
接口; 所有类型的猫都实现猫
接口, 以此类推。
如下类图所示(忽略画图太丑~ ~):各种类型的狗都来实现狗
这个接口。

WhiteDog
java
public class WhiteDog implements IDog{
@Override
public void eat() {
System.out.println("我是 WhiteDog ~~~");
}
}
BlackDog
typescript
public class BlackDog implements IDog{
@Override
public void eat() {
System.out.println("我是 BlackDog~~~~");
}
}
实现ICat的,就省略了,跟实现IDog相同,名称换一下即可
此时我们就想了,能不能有一个东西(工厂),不管是什么类型的动物,例如:猫,狗,我们只需要调用抽象
接口,就能返回给我们的是白猫
或者是白狗
。此时就引出抽象工厂了
------包含系列中所有产品构造方法的接口。例如:createCat
和createDog
。这些方法必须返回抽象 产品类型, 即我们之前抽取的那些接口:IDog
和ICat
。如下代码所示:
java
public interface IAnimalFactory {
/**
* 定义创建Icat接口实例的方法
*/
ICat createCat();
/**
* 定义创建IDog接口实例的方法
*/
IDog createDog();
}
此时有的小伙伴就说了,那我现在调用了createCat()
能给我一个白猫嘛
,目前当然不能啦,接着往下看。
此时我们已经有了抽象工厂了,你可以想象成这是一个动物世界
包含任意一种类型的动物。那么该如何处理动物的变体呢(也就是我们需要特殊的,比如猫类中的白猫
呢)? 对于系列产品的每个变体, 我们都将基于 抽象工厂(IAnimalFactory)
接口创建不同的工厂类。 每个工厂类都只能返回特定类别的产品。如下代码:
java
// 变体的工厂,都需要实现抽象工厂
public class WhiteAnimalFactory implements IAnimalFactory {
public ICat createCat() {
// 返回的是具体的实现类,并非抽象的
return new WhiteCat();
}
public IDog createDog() {
return new WhiteDog();
}
}
也就只能创建出WhiteCat
和 WhiteDog
java
public class BlackAnimalFactory implements IAnimalFactory {
public ICat createCat() {
return new BlackCat();
}
public IDog createDog() {
return new BlackDog();
}
}
让我们来测试一下吧
假设客户端想要工厂创建一个Dog
。 客户端无需了解工厂类, 也不用管工厂类创建出的Dog
类型。 无论是白色
, 还是黑色
的Dog
, 对于客户端来说没有分别, 它只需调用抽象 IDog
接口就可以了。 这样一来, 客户端只需知道Dog
以某种方式实现了 eat
方法就足够了。 此外, 无论工厂返回的是何种Dog
变体, 它都会和由同一工厂对象创建的Cat
风格或者是颜色一致。如下代码所示:
ini
public class Test {
public static void main(String[] args) {
// 创建了一个BlackAnimalFactory工厂
IAnimalFactory blackAnimalFactory = new BlackAnimalFactory();
ICat blackCat = blackAnimalFactory.createCat();
// 此时调用的是具体实现了ICat的BlackCat中的eat方法
blackCat.eat();
IDog blackDog = blackAnimalFactory.createDog();
blackDog.eat();
IAnimalFactory whiteAnimalFactory = new WhiteAnimalFactory();
ICat whiteCat = whiteAnimalFactory.createCat();
whiteCat.eat();
IDog whiteDog = whiteAnimalFactory.createDog();
whiteDog.eat();
}
}

如果小伙伴们看上面的代码有点绕不太理解,可以去看看面向接口编程的帖子,来了解为什么可以这样书写。
日常提问: 小伙伴们可以讨论在spring中哪些使用到了抽象工厂吗?欢迎评论讨论学习~~
附加问题:小伙伴们看看如下代码,在没有执行测试类,大家能看出来会有什么问题吗?为什么会这样呢?
java
public class Father {
public Father() {
start();
}
protected void start() {}
}
java
public class Child extends Father {
private Integer i;
public Child() {
i = 1;
start();
}
@Override
public void start() {
System.out.println(i.byteValue());
}
}
typescript
public class TestF {
public static void main(String[] args) {
Child child = new Child();
child.start();
}
}
今日划水结束,准备下班喽~~~~