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

一、简单工厂模式

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

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

类关系图如下:
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、这时候考虑变化,我们认为调料是变化的,就会出现新的调料,比如生抽。

评论

加载中...
|