工厂模式(FactoryPattern)

场景

生产AK47、M4A1、M16这三种枪械

简单工厂

具体产品类

1
2
3
4
5
6
7
8
public interface Rifle {
// 射击
void fire();
// 装弹中
void reloading();
// 特性
void trait();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AK47 implements Rifle {
@Override
public void fire() {
System.out.println("AK47射击 -- 哒哒哒哒哒哒");
}

@Override
public void reloading() {
System.out.println("Ak47 填充弹夹");
}

@Override
public void trait() {
System.out.println("Ak47 威力大,后坐力大!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class M4A1 implements Rifle {
@Override
public void fire() {
System.out.println("M4A1射击 -- 哔哔哔哔哔哔");
}

@Override
public void reloading() {
System.out.println("M4A1 填充弹夹");
}

@Override
public void trait() {
System.out.println("M4A1 射程远,射速快!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class M16 implements Rifle {
@Override
public void fire() {
System.out.println("M16射击 -- 嘤嘤嘤嘤嘤嘤");
}

@Override
public void reloading() {
System.out.println("M16 填充弹夹");
}

@Override
public void trait() {
System.out.println("M16 后坐力低,精度高!!!");
}
}

简单工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RifleFactory {
public static <T extends Rifle> T getRifle(Class<?> c) {
Rifle rifle = null;
try {
// 通过反射来生成对象,而不是传输一个字符串比较,符合开闭原则
rifle = (Rifle) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) rifle;
}
}

测试类

1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
AK47 ak47 = RifleFactory.getRifle(AK47.class); // 通过工厂获取一把AK47
ak47.reloading(); // 填充子弹
ak47.fire(); // 射击
ak47.trait(); // ...
}
}

小结

简单工厂比较简单,如果获得某个类的对象的时候直接获取不需要其它的一些特殊处理,则可以使用这个简单工厂模式,需要对不同的类进行定制处理,则这个工厂显得过于冗余,不好处理!!!

工厂方法

具体产品类

与简单工厂中相同!!!

工厂方法

定义一个抽象工厂或者接口,我比较喜欢用接口。

1
2
3
public interface AbstractRifleFactory {
<T extends Rifle> T createRifle();
}
1
2
3
4
5
6
public class AK47Factory implements AbstractRifleFactory {
@Override
public <T extends Rifle> T createRifle() {
return (T) new AK47();
}
}
1
2
3
4
5
6
public class M4A1Factory implements AbstractRifleFactory {
@Override
public <T extends Rifle> T createRifle() {
return (T) new M4A1();
}
}
1
2
3
4
5
6
public class M16Factory implements AbstractRifleFactory {
@Override
public <T extends Rifle> T createRifle() {
return (T) new M16();
}
}

测试类

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {
AK47Factory ak47Factory = new AK47Factory(); // 只需知道AK47工厂便可得到其对象
AK47 ak47 = ak47Factory.createRifle(); // 来一把AK47
ak47.reloading();
ak47.fire();
ak47.trait();
}
}

小结

工厂模式相较简单工厂具体的生产交由子类来实现,每个工厂职责单一,可对每个产品生产做特殊处理也不至于显得冗余,但是这个扩展的话增加的类你不感觉太多了吧,容易造成类爆炸,上述例子比较简单,如果在不同步枪的基础上,还需要添加国家这个条件呢,俄罗斯AK47,俄罗斯M4A1,美国AK47,美国M4A1等等。。这就需要轮到抽象工厂上场了。

抽象工厂

现在需求发生变化,每个步枪都由俄罗斯和美国来制作,生产时要知道我这是俄罗斯AK47还是美国制造。

这里需要知道产品族的概念,这个概念比较简单。你根据国家来分的话,比如俄罗斯的AK47,M4A1,M16都是俄罗斯生产的他们是一个产品族。然后根据步枪的种类来分的话,俄罗斯的AK47,美国的AK47是一个产品族,看具体要求的场景了。反正比较灵活。

具体的产品类

1
2
3
4
5
6
7
8
public interface Rifle {
// 射击
void fire();
// 装弹中
void reloading();
// 特性
void trait();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class USAM16 implements Rifle {
@Override
public void fire() {
System.out.println("USA M16射击 -- 嘤嘤嘤嘤嘤嘤");
}

@Override
public void reloading() {
System.out.println("USA M16 填充弹夹");
}

@Override
public void trait() {
System.out.println("USA M16 后坐力低,精度高!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class USAM4A1 implements Rifle {
@Override
public void fire() {
System.out.println("USA M4A1射击 -- 哔哔哔哔哔哔");
}

@Override
public void reloading() {
System.out.println("USA M4A1 填充弹夹");
}

@Override
public void trait() {
System.out.println("USA M4A1 射程远,射速快!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class USAAK47 implements Rifle {
@Override
public void fire() {
System.out.println("USA AK47射击 -- 哒哒哒哒哒哒");
}

@Override
public void reloading() {
System.out.println("USA Ak47 填充弹夹");
}

@Override
public void trait() {
System.out.println("USA Ak47 威力大,后坐力大!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RussiaM16 implements Rifle {
@Override
public void fire() {
System.out.println("Russia M16射击 -- 嘤嘤嘤嘤嘤嘤");
}

@Override
public void reloading() {
System.out.println("Russia M16 填充弹夹");
}

@Override
public void trait() {
System.out.println("Russia M16 后坐力低,精度高!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RussiaM4A1 implements Rifle {
@Override
public void fire() {
System.out.println("Russia M4A1射击 -- 哔哔哔哔哔哔");
}

@Override
public void reloading() {
System.out.println("Russia M4A1 填充弹夹");
}

@Override
public void trait() {
System.out.println("Russia M4A1 射程远,射速快!!!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RussiaAK47 implements Rifle {
@Override
public void fire() {
System.out.println("Russia AK47射击 -- 哒哒哒哒哒哒");
}

@Override
public void reloading() {
System.out.println("Russia Ak47 填充弹夹");
}

@Override
public void trait() {
System.out.println("Russia Ak47 威力大,后坐力大!!!");
}
}

抽象工厂

这里我根据枪械来分类,所以要创建3个不同枪械的工厂,根据国家的话创建两个工厂就够了!!!

1
2
3
4
5
6
7
public interface RifleFactory {
// 创建俄罗斯步枪
<T extends Rifle> T createRussiaRifle();

// 创建美国步枪
<T extends Rifle> T createUSARifle();
}
1
2
3
4
5
6
7
8
9
10
11
public class M16Factory implements RifleFactory {
@Override
public <T extends Rifle> T createRussiaRifle() {
return (T) new RussiaM16();
}

@Override
public <T extends Rifle> T createUSARifle() {
return (T) new USAM16();
}
}
1
2
3
4
5
6
7
8
9
10
11
public class M4A1Factory implements RifleFactory {
@Override
public <T extends Rifle> T createRussiaRifle() {
return (T) new RussiaM4A1();
}

@Override
public <T extends Rifle> T createUSARifle() {
return (T) new USAM4A1();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class AK47Factory implements RifleFactory {

@Override
public <T extends Rifle> T createRussiaRifle() {
return (T) new RussiaAK47();
}

@Override
public <T extends Rifle> T createUSARifle() {
return (T) new USAAK47();
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test {
public static void main(String[] args) {
// AK47生产线
AK47Factory ak47Factory = new AK47Factory();
RussiaAK47 russiaAK47 = ak47Factory.createRussiaRifle();
russiaAK47.reloading();
russiaAK47.fire();
russiaAK47.trait();
System.out.println("====================================");
// M4A1生产线
M4A1Factory m4A1Factory = new M4A1Factory();
USAM4A1 usam4A1 = m4A1Factory.createUSARifle();
usam4A1.reloading();
usam4A1.fire();
usam4A1.trait();
}
}

小结

抽象工厂解决了工厂方法,由于条件变成二维导致类产生急剧增多的问题,如果这个需求按照工厂方法来写则需要创建6个工厂,抽象方法创建3个就可,减少了类,但是这个抽象方法有个缺点就是,如果加入一个中国制造那就需要在那个接口中添加一个中国制造的方法,所有实现这个接口的类都需要修改,就违反了开闭原则,横向容易扩展,假如你现在添加一个QBZ95步枪生产线就很容易。纵向不容易扩展,根据具体的场景选择使用。

个人理解

简单工厂主要将各个产品的创造全部集中到了一个工厂中,通过反射类符合开闭原则。

工厂方法是定义一个抽象工厂类,不同产品对应不同的工厂,继承抽象工厂类来生产不同的产品。

抽象工厂解决的是工厂方法应对二维条件,会产生过多的工厂的问题,但是抽象工厂纵向不易拓展。

这三种都不是最完美的,各有优缺点,具体场景具体使用!