系列文章目录
肝一肝设计模式【一】-- 单例模式 传送门
肝一肝设计模式【二】-- 工厂模式 传送门
文章目录
- 系列文章目录
- 前言
- 一、简单工厂模式
- 二、工厂方法模式
- 三、抽象工厂模式
- 写在最后
前言
在实际开发过程中,构建对象往往使用new的方式来构建,但随着开发时间的拉长,构建对象的逻辑慢慢会在很多类里使用,那就势必会产生大量的重复代码,那就意味着难以维护,所以我们想把创建对象的代码和业务逻辑分离,并通过一个统一的接口创建对象,然后把创建对象的逻辑封装起来,而这些就是工厂模式所解决的问题
一、简单工厂模式
我们拿动物世界举个栗子(最近陪女鹅看动画片看太多,脑子第一时间想到的只有动物o(* ̄3 ̄)o )
我们先定义一个Animal接口
public interface Animal {
public void eat();
}
然后再创建两个实现类兔子和老虎
public class Rabbit implements Animal {
@Override
public void eat() {
System.out.println("我是兔子,我吃胡萝卜");
}
}
public class Tiger implements Animal {
@Override
public void eat() {
System.out.println("我是老虎,我吃肉");
}
}
再创建一个AnimalFactory工厂类,有两种方式实现:
- 使用逻辑判断方式
public class AnimalFactory {
public Animal create(String name) {
if("rabbit".equals(name)) {
return new Rabbit();
} else if("tiger".equals(name)) {
return new Tiger();
} else {
System.out.println("啥也不是");
return null;
}
}
}
然后我们测试一下:
public class SimpleFactoryTest {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
factory.create("rabbit").eat();
}
}
也可将AnimalFactory工厂类的create()方法改为静态方法,这样调用就更方便一点。
- 使用反射方式
public class AnimalFactory {
public Animal create(Class<? extends Animal> c){
try {
if (null != c) {
return c.newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
我们测试一下:
public class SimpleFactoryTest {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.create(Tiger.class);
animal.eat();
}
}
简单工厂模式实质:是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
二、工厂方法模式
在简单的工厂模式里,我们创建了一个类似工具的类来创建相应的具体类对象,但正因为其太过简单,不符合开闭原则。
工厂方法模式就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层 + 具体的工厂子类层。
我们上面的工厂类进行拆分
- AnimalFactory(抽象工厂)
public abstract class AnimalFactory {
public abstract Animal create();
}
- RabbitFactory(具体的工厂子类)‘
public class RabbitFactory extends AnimalFactory {
@Override
public Animal create() {
return new Rabbit();
}
}
- TigerFactory(具体的工厂子类)
public class TigerFactory extends AnimalFactory {
@Override
public Animal create() {
return new Tiger();
}
}
测试一下
public class FactoryMethodTest {
public static void main(String[] args) {
AnimalFactory factory = new RabbitFactory();
Rabbit rabbit = factory.create();
rabbit.eat();
}
}
工厂方法模式实质:不仅仅产品要抽象, 工厂也需要抽象。这样的好处就是更拥抱变化,比如现在需要创建一个Cat对象,就不需要像简单工厂模式去修改create()方法,只需新增一个Cat工厂类即可,遵循了开闭原则。
三、抽象工厂模式
工厂方法模式中,具体工厂A和B,两者除了都是抽象工厂的子类,没有任何其他的交集,是完全独立的两个工厂。
那抽象工厂模式中,具体工厂之间就能产生交际。
抽象工厂模式是这么定义的,提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。可以理解为将同一类的产品子类归为一类,让他们继承同一个抽象子类,把他们当做一个组。
比如我们新增一个Cat类,我们可以把猫和兔子分类成宠物类型,也可以把猫和老虎分类成猫科动物类型。
所以代码修改一下:
public class AbstractFactoryClient {
public static void main(String[] args) {
AnimalFactory factory = new PetFactory();
factory.createPet().sayA();
factory.createMaoke().sayB();
factory = new MaokeFactory();
factory.createPet().sayA();
factory.createMaoke().sayB();
}
// 抽象工厂类
public interface AnimalFactory {
Pet createPet();
Maoke createMaoke();
}
// 宠物分类抽象
public interface Pet {
void sayA();
}
// 猫科分类抽象
public interface Maoke {
void sayB();
}
// 宠物分类的兔子
static class RabbitWithPet implements Pet {
@Override
public void sayA() {
System.out.println("我是宠物兔");
}
}
// 宠物分类的猫
static class CatWithPet implements Pet {
@Override
public void sayA() {
System.out.println("我是宠物猫");
}
}
// 猫科分类的猫
static class CatWithMaoke implements Maoke {
@Override
public void sayB() {
System.out.println("我能上树,所以我是猫科动物的老大");
}
}
// 猫科分类的老虎
static class TigerWithMaoke implements Maoke {
@Override
public void sayB() {
System.out.println("老大没教我怎么上树");
}
}
// 具体工厂类(宠物)
static class PetFactory implements AnimalFactory{
@Override
public Pet createPet() {
return new RabbitWithPet();
}
@Override
public Maoke createMaoke() {
return new CatWithMaoke();
}
}
// 具体工厂类(猫科)
static class MaokeFactory implements AnimalFactory{
@Override
public Pet createPet() {
return new CatWithPet();
}
@Override
public Maoke createMaoke() {
return new TigerWithMaoke();
}
}
}
在抽象工厂模式中,可以不需要知道产品是什么样的,只需要知道是用哪个工厂类就行了。也可以根据子类的共同特性,将它们设计在一起,组成一个相同类型组,就可以很方便的直接调用。但是相对的,产品族比较难以扩展,增加一个产品,就需要增加相应的接口和实现类。
写在最后
工厂模式关心的是最终创建的对象,而不关心创建的过程,这样做的优点是为创建对象提供统一的接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的,在此同时还能给系统带来更大的可扩展性和尽量少的修改量。