喵星之旅-沉睡的猫咪-工厂类型设计模式

一、简单工厂模式

创建一个工厂类,里面写方法负责创建对象。提供创建实例的功能,而无需关心具体实现。锅是由调用者和工厂一起负责的。

由于如果创建一个对象,不单是工厂类内部的问题,调用者往里面传入信息了,所以一旦出现问题是双方的问题。他解耦的结果是虽然锅没彻底甩出去,但是找了一个一起背锅的。

类关系图如下:
Alt text

产品接口:

1
2
3
4
5
package create.simplefactory;

public interface Food {
public void cook();
}

具体产品1:

1
2
3
4
5
6
7
package create.simplefactory;

public class Jiucaijidan implements Food {
public void cook() {
System.out.println("韭菜鸡蛋做好了");
}
}

具体产品2:

1
2
3
4
5
6
7
package create.simplefactory;

public class Xihongshijidan implements Food {
public void cook() {
System.out.println("西红柿鸡蛋做好了");
}
}

工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package create.simplefactory;

public class FoodFactory {
public Food createByName(String name) {
if ("Jiucaijidan".equals(name)) {
return new Jiucaijidan();
} else if ("Xihongshijidan".equals(name)) {
return new Xihongshijidan();
}
return null;
}
public Food createByClassname(String name) {
try {
if (name != null && !"".equals(name)) {
return (Food) Class.forName(name).newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Food createByClass(Class<? extends Food> clazz) {
try {
if (clazz != null) {
return clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package create.simplefactory;

public class Test {

public static void main(String[] args) {
Food f1 = new FoodFactory().createByName("Jiucaijidan");
f1.cook();

Food f2 = new FoodFactory().createByClassname("create.simplefactory.Xihongshijidan");
f2.cook();

Food f3 = new FoodFactory().createByClass(Xihongshijidan.class);
f3.cook();
}

}

二、工厂模式

对上面的进行包装,将类型相同、有关联的放在一起,上面创建接口,外界通过接口使用工厂。让工厂彻底成为背锅侠。这里使用工厂时,已经不需要调用者参与了,所以除了问题都是工厂相关的,完美甩锅。

关系图如下:

Alt text

产品接口:

1
2
3
4
5
package create.factory;

public interface Food {
public void cook();
}

具体产品1:

1
2
3
4
5
6
7
package create.factory;

public class Jiucaijidan implements Food {
public void cook() {
System.out.println("韭菜鸡蛋做好了");
}
}

具体产品2:

1
2
3
4
5
6
7
package create.factory;

public class Xihongshijidan implements Food {
public void cook() {
System.out.println("西红柿鸡蛋做好了");
}
}

工厂接口:

1
2
3
4
5
package create.factory;

public interface FoodFactory {
public Food create();
}

具体工厂1:

1
2
3
4
5
6
7
8
9
package create.factory;

public class JiucaiFactory implements FoodFactory {
public Food create() {

return new Jiucaijidan();

}
}

具体工厂2:

1
2
3
4
5
6
7
8
package create.factory;

public class XihongshiFactory implements FoodFactory {
public Food create() {
return new Xihongshijidan();

}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package create.factory;

public class Test {

public static void main(String[] args) {
FoodFactory ff1 = new XihongshiFactory();
FoodFactory ff2 = new JiucaiFactory();
Food f1 = ff1.create();
Food f2 = ff2.create();
f1.cook();
f2.cook();

}

}

三、抽象工厂模式

考虑工厂的出现,将里面的简单工厂用工厂替换,就是抽象工厂。而且可以出现多级抽象工厂。

如果工厂进行背锅,里面有一些质量好的工厂就会有意见,所以内部分裂了,内部进行甩锅,就是抽象工厂。工厂总接口越稳定、内部背锅规则越详细,那么甩锅的设计就更完善、这个抽象工厂越成功。

关系图如下(只是其中一种展现方式):

Alt text

具体产品1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package create.abstractfactory;

public class XiangyouJiucaijidan implements Condiment,Food {

@Override
public void add() {
System.out.println("添加香油的");
}

@Override
public void cook() {
System.out.println("韭菜鸡蛋做好了");
}

}

具体产品2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package create.abstractfactory;

public class XiangyouXihongshijidan implements Condiment, Food {

@Override
public void add() {
System.out.println("添加香油的");
}

@Override
public void cook() {
System.out.println("西红柿鸡蛋。");

}

}

具体产品3:

1
2
3
4
5
6
7
8
9
10
11
12
package create.abstractfactory;

public class JijingJiucaijidan implements Food, Condiment {
public void cook() {
System.out.println("韭菜鸡蛋做好了");
}

@Override
public void add() {
System.out.println("添加鸡精。");
}
}

具体产品4:

1
2
3
4
5
6
7
8
9
10
11
12
13
package create.abstractfactory;

public class JijingXihongshijidan implements Food, Condiment {
public void cook() {
System.out.println("西红柿鸡蛋做好了");
}

@Override
public void add() {
System.out.println("添加鸡精。");

}
}

产品分类1:

1
2
3
4
5
package create.abstractfactory;

public interface Condiment {
void add();
}

产品分类2:

1
2
3
4
5
package create.abstractfactory;

public interface Food {
public void cook();
}

总产品接口:

1
2
3
4
5
6
package create.abstractfactory;

public interface CookFactory {
public Food createXihongshijidan() ;
public Food createJiucaijidan() ;
}

分类产品工厂1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package create.abstractfactory;

public class JijingFactory implements CookFactory {
public Food createXihongshijidan() {

return new JijingXihongshijidan();

}
public Food createJiucaijidan() {

return new JijingJiucaijidan();

}
}

分类产品工厂2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package create.abstractfactory;

public class XiangyouFactory implements CookFactory {
public Food createXihongshijidan() {

return new XiangyouXihongshijidan();

}
public Food createJiucaijidan() {

return new XiangyouJiucaijidan();

}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package create.abstractfactory;

public class Test {

public static void main(String[] args) {
CookFactory ff1 = new JijingFactory();
CookFactory ff2 = new XiangyouFactory();
Food f1 = ff1.createXihongshijidan();
Food f2 = ff2.createXihongshijidan();

f1.cook();
f2.cook();

}

}

四、多级抽象工厂模式

考虑工厂模式,将简单工厂用抽象工厂替换。

如果工厂接口层级较高,需要考虑如果尽量少的改动上方接口进行接口分层,胡乱分层会出问题。层级越靠上的改动频率应该越低。

对于工厂之上的抽象系列,也可能是单纯的工厂里面进行产品分类形成的,可能是多个工厂合道一起也可能是一个工厂拆分。如果是拆分就看拆分的详细程度,决定了抽象程度。不管是合并还是拆分,其实都需要重构。想要一开始就设计完美是不可能的.

五、抽象工厂的实现步骤(以上面的抽象工厂为例)

1、分析具体的产品特性,找出2中不同类别的特征。

比如:香油的韭菜鸡蛋、鸡精的韭菜鸡蛋、香油的西红柿鸡蛋、鸡精的西红柿鸡蛋。

那么一个菜可以有主料和调两部分。

2、考虑2类特性那一个变化的几率比较低。

我个人认为调料新品种的出现会频率更高,那么就认为主料的变化相对固定。

3、根据变化频率低的创建总接口

接口:菜肴

里面两个方法:做一个西红柿鸡蛋

做一个韭菜鸡蛋

如果认为是调料稳定,那么这里应该是两外的两个方法:添加香油的食物、添加鸡精的食物。

4、根据总接口和具体菜肴,创建不同的工厂类

第一个工厂往里面添加香油

第二个工厂往里面添加鸡精

5、这时候考虑变化,我们认为调料是变化的,就会出现新的调料,比如生抽。

那么我们的变化是总接口不变化!!,然后添加一个新的工厂类。

如果总接口先变化,那么说明设计错误。

文章目录
  1. 一、简单工厂模式
  2. 二、工厂模式
  3. 三、抽象工厂模式
  4. 四、多级抽象工厂模式
  5. 五、抽象工厂的实现步骤(以上面的抽象工厂为例)
    1. 1、分析具体的产品特性,找出2中不同类别的特征。
    2. 2、考虑2类特性那一个变化的几率比较低。
    3. 3、根据变化频率低的创建总接口
    4. 4、根据总接口和具体菜肴,创建不同的工厂类
    5. 5、这时候考虑变化,我们认为调料是变化的,就会出现新的调料,比如生抽。
|