创建型之工厂模式
序言
工厂模式作为创建多例对象的一种设计思想,避免了面向过程一泻千里的糟糕写法,扩展性和可维护性都很强,值得我们好好学习。
工厂模式大致分为3类,分别是简单工厂、工厂方法、抽象工厂,下面就自己的理解,总结一下。入笔之前,先阐述几个不知所云的概念。
- 抽象工厂类角色:接口或者抽象类,所有的具体工厂类都要实现或继承该类
- 具体工厂类角色:具体类,new对象的逻辑都在这里,调用者只需调用该静态方法
- 抽象产品角色:接口或者抽象类,为调用者提供行为方法
- 具体产品角色:具体类,真正被new的对象,调用者无需亲自创建,一切皆由静态工厂方法处理
1. 简单工厂
简单工厂的基本结构如下图:
套路:
1. 要生成多个相似功能的产品,但不同的产品的具体功能不同,即要有继承或者实现接口
2. 添加1个具体工厂类,添加1个静态工厂方法
/**
* 抽象产品角色
*/
public interface Fruit {
void grow();
}
/**
* 具体产品角色
*/
public class Apple implements Fruit {
public void grow() {
System.out.println("apple growed");
}
}
/**
* 具体产品橘色
*/
public class Banana implements Fruit {
public void grow() {
System.out.println("banana growed");
}
}
/**
* 工厂类
*/
public class FruitFactory {
public static Fruit createFruit(String fruitName){
if("apple".equals(fruitName)){
return new Apple();
}
if("banaa".equals(fruitName)){
return new Banana();
}
throw new RuntimeException("fruitName not exits");
}
public static <T extends Fruit> T createFruit(Class<T> clazz){
T fruit = null;
try {
fruit = (T) Class.forName(clazz.getName()).newInstance();
return fruit;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
public class SimpleFactoryTest {
@Test
public void testSimpleFactory(){
Fruit apple = FruitFactory.createFruit("apple");
apple.grow();
Banana banana = FruitFactory.createFruit(Banana.class);
banana.grow();
}
}
吹牛:增加工厂类后,调用者无需亲自创建对象,通过静态工厂方法拿到对象后,直接调用其行为方法,如果再增加葡萄产品时,只需写一个Grape类,实现Fruit接口,在Factory增加1个if即可,无需修改客户端代码。不好的地方在于,静态工厂方法承担的任务太重,当产品越来越多时,该方法会变得又臭又长。
2. 工厂方法
工厂方法基本结构图如下:
套路:
1. 要生产多个相似功能的产品,但通过分类,还可以分为几大类的生产者
2. 添加1个抽象工厂类或者接口,添加多个具体生产工厂,工厂里的方法都是实例方法
3. 客户端调用时,直接new对应的factory,然后传参数调用其实例方法
/**
* 产品接口
*/
public interface Animal {
void run();
}
/**
* 具体产品,4条腿
*/
public class Panada implements Animal{
public void run() {
System.out.println("panada is running ...");
}
}
/**
* 具体产品,4条腿
*/
public class Tigger implements Animal{
public void run() {
System.out.println("tigger is running ...");
}
}
/**
* 具体产品,2条腿
*/
public class Human implements Animal{
public void run() {
System.out.println("human is runging ....");
}
}
/**
* 具体产品,2条腿
*/
public class Penguin implements Animal {
public void run() {
System.out.println("penguin is running ...");
}
}
/**
* 抽象工厂接口
*/
public interface AnimalFactory {
Animal createAnimal(String animalName);
}
/**
* 具体工厂,两条腿
*/
public class TwoLegsAnimalFactory implements AnimalFactory{
public Animal createAnimal(String animalName) {
if("human".equals(animalName)){
return new Human();
}
if("penguin".equals(animalName)){
return new Penguin();
}
throw new RuntimeException("not extists this four legs");
}
}
/**
* 具体工厂,4条腿
*/
public class FourLegsAnimalFactory implements AnimalFactory{
public Animal createAnimal(String animalName) {
if("tigger".equals(animalName)){
return new Tigger();
}
if("panada".equals(animalName)){
return new Panada();
}
throw new RuntimeException("not extists this four legs");
}
}
/**
* 测试工厂方法
*/
public class FactoryMethodTest {
@Test
public void testFactoryMethod(){
AnimalFactory fourLegsAnimalFactory = new FourLegsAnimalFactory();
fourLegsAnimalFactory.createAnimal("tigger").run();
fourLegsAnimalFactory.createAnimal("panada").run();
TwoLegsAnimalFactory twoLegsAnimalFactory = new TwoLegsAnimalFactory();
twoLegsAnimalFactory.createAnimal("penguin").run();
twoLegsAnimalFactory.createAnimal("human").run();
}
}
吹牛:如果系统需要增加一个新产品,那么只需要向系统增加一个具体产品类,及其对应的具体工厂类,无需修改抽象工厂类,无需修改其它具体工厂类,也无需修改客户端。
3. 抽象工厂
抽象工厂的具体结构图如下:
套路:
1. 添加新的产品,增加抽象产品,以及其对应的具体产品类
2. 在工厂方法模式下,修改具体工厂方法名称,用产品名称命名
3. 在抽象工厂接口里添加生产具体产品的方法
/**
* 抽象产品-电脑
*/
public interface Computer {
public String getComputerInfo();
}
/**
* 抽象产品-手机
*/
public interface Phone {
public String getPhoneInfo();
}
/**
* 具体产品-苹果电脑
*/
public class AppleComputer implements Computer{
public String getComputerInfo() {
return "mac pro 12 is using";
}
}
/**
* 具体工厂-三星电脑
*/
public class SamsungComputer implements Computer{
public String getComputerInfo() {
return "samsung 900X3N-K09 is using";
}
}
/**
* 具体产品-苹果手机
*/
public class ApplePhone implements Phone{
public String getPhoneInfo() {
return "iphone 8 is using";
}
}
/**
* 具体产品-三星手机
*/
public class SamsungPhone implements Phone {
public String getPhoneInfo() {
return "samsung galaxy s8 is usging";
}
}
/**
* 抽象工厂
*/
public interface ElectronicFactory {
public Phone createPhone();
public Computer createComputer();
}
/**
* 具体工厂-苹果,以品牌厂家分类,即apple和samsung,而不是具体产品分类,即computer和phone
*/
public class AppleFactory implements ElectronicFactory{
public Phone createPhone() {
return new ApplePhone();
}
public Computer createComputer() {
return new AppleComputer();
}
}
/**
* 具体工厂-三星,以品牌厂家分类,即apple和samsung,而不是具体产品分类,即computer和phone
*/
public class SamsungFactory implements ElectronicFactory{
public Phone createPhone() {
return new SamsungPhone();
}
public Computer createComputer() {
return new SamsungComputer();
}
}
/**
* 抽象工厂测试
*/
public class AbstractFactoryTest {
@Test
public void testAbstractFactory(){
ElectronicFactory appleFactory = new AppleFactory();
appleFactory.createPhone().getPhoneInfo();
appleFactory.createComputer().getComputerInfo();
ElectronicFactory samsungFactory = new SamsungFactory();
samsungFactory.createPhone().getPhoneInfo();
samsungFactory.createComputer().getComputerInfo();
}
}
吹牛:如果系统需要增加一个新的产品族,如新厂家或者新品牌,再增加一个品牌的具体工厂方法即可,无需修改原来的抽象工厂类和具体工厂类,也无需修改客户端,缺点是如果增加一个新的产品时,即添加一个抽象类及其对应的具体产品类的产品树时,原来的抽象工厂和具体工厂都要修改。
4. 总结
- 简单工厂: 用来生产同一品牌下的不同但具有相似功能的产品;扩展性差,增加产品时,必须得修改原来具体工厂。
- 工厂方法: 用来生产同一品牌下的不同中但具有相似功能的产品;扩展性强,增加产品时,不需要修改具体工厂。
- 抽象工厂: 用来生产不同品牌下的不同但具有相似功能的产品;增加品牌时,扩展性强;增加产品时,扩展性差,必须得修改原来的抽象和具体工厂。
后记
转载时,注明出处是人格的一种体现。
https://www.zybuluo.com/BertLee/note/837738
能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。