这是我设计模式系列的第一篇总结。
首先讲一下为什么需要使用工厂设计模式?
我们平时正常开发编码的时候创建对象有几种方式:
1.直接new
2.使用Class类的newInstance方法
3.使用Constructor类的newInstance方法
4.使用clone
5.使用序列化
最常见的就是第一种new的方式。但是有的时候往往创建对象和使用对象在同一个类当中。这就导致了这个类的任务很繁重,并且职责不清晰。并且违反了"开闭原则"。所以我们就要把创建对象和使用对象两个职责分离开,这样我们就引入了“工厂”的概念。我们把创建对象的任务交给“工厂”来做,什么时候用就直接从工厂中拿。
我们常说的工厂设计模式有“简单工厂模式”、“工厂模式”、和“抽象工厂模式”。
工厂三兄弟我从简单到复杂(简单到抽象)进行总结。
一.简单工厂模式
简单工厂模式定义如下:
简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
我们围绕着一个购买Nike和Adidas产品的例子实现接下来的三种工厂模式。
首先简单工厂模式顾名思义他的结构比较简单,那么适用于需要的对象比较少并且简单的情况下。
1.Shoes 抽象产品接口:这个接口代表了所有工厂最终生产出具体类的父类。
2.NikeShoes、AdidasShoes 具体产品实现类:抽象产品接口的实现类,这里包含了具体方法的实现、自己的构造方法、初始化一些信息等。
3.ShoesFactory 工厂方法类:整个当中最核心的类。此类包含了选择创建对象的逻辑。
//抽象产品接口
public interface Shoes {
//共有方法
void display();
}
//Nike商品
public class NikeShoes implements Shoes {
@Override
public void display() {
System.out.println("耐克鞋~~~");
}
}
//Adidas商品
public class AdidasShoes implements Shoes {
@Override
public void display() {
System.out.println("阿迪达斯鞋~~~");
}
}
//工厂
public class ShoesFactory {
public static Shoes getShoes(String brand) {
if (brand.equalsIgnoreCase("nike")) {
return new NikeShoes();
} else if (brand.equalsIgnoreCase("adidas")) {
return new AdidasShoes();
} else {
return null;
}
}
}
//购买鞋子入口函数
public class BuyShoes {
public static void main(String args[]) {
Shoes shoes = ShoesFactory.getShoes("nike");
shoes.display();
}
}
//输出
-------------
//耐克鞋~~~
我们可以看到这个工厂类通过传入的参数来选择创建具体类型的对象并且返回。
二.工厂方法模式
接下来是工厂三兄弟的老二——“工厂方法模式”。
这个老二又是怎样的需求促使它诞生的呢?
我们回忆一下刚才的老三"简单工厂模式",它适用于创建的对象类型较少的情况下。但是它有一个致命的缺点就是工厂类中的任务太重了,如果对象的类型较多,则需要写很多的if... else...,如果某一个类型改变了,就要回过头来去修改工厂中的逻辑代码,这样很不方便。把简单工厂稍微抽象一下,就诞生了我们的工厂方法模式来解决这样的问题。
工厂方法模式定义:
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。
工厂方法模式
1.ShoesFactory 抽象工厂:有别于简单工厂这里多了一个“抽象工厂”接口。接口中声明了创建具体产品的方法。返回值是抽象的产品接口类型。
2.NikeShoesFactory、AdidasShoesFactory 具体工厂类:实现抽象工厂接口,并实现创建对象的方法,各个不同的具体工厂生产自己的具体产品。
3.产品接口和实现类与简单工厂几乎相同。
package Factory;
//抽象商品接口
public interface Shoes {
void display();
}
//Nike商品实现类
public class NikeShoes implements Shoes {
@Override
public void display() {
System.out.println("耐克鞋~~~");
}
}
//Adidas商品实现类
public class AdidasShoes implements Shoes {
@Override
public void display() {
System.out.println("阿迪达斯鞋~~~");
}
}
//抽象工厂
public interface ShoesFactory {
Shoes getShoes();
}
// Nike工厂
public class NikeShoesFactory implements ShoesFactory {
@Override
public Shoes getShoes() {
return new NikeShoes();
}
}
// Adidas工厂
public class AdidasShoesFactory implements ShoesFactory {
@Override
public Shoes getShoes() {
return new AdidasShoes();
}
}
//购买函数
public class BuyShoes {
public static void main(String args[]) {
ShoesFactory nikeShoesFactory = new NikeShoesFactory();
Shoes nikeShoes = nikeShoesFactory.getShoes();
nikeShoes.display();
ShoesFactory adidasShoesFactory = new AdidasShoesFactory();
Shoes adidasShoes = adidasShoesFactory.getShoes();
adidasShoes.display();
}
}
//输出
-----------
//耐克鞋~~~
//阿迪达斯鞋~~~
我们可以看到这种优化后的模式具体的产品从相对应的具体工厂生产,如果有新的产品,就横向增加新的工厂即可,删除同理不会横向纵向的影响代码结构,满足的了"开闭原则"。
那么我们想想这样的模式还存在什么弊端呢?
三.抽象工厂
工厂三兄弟的老大,也是真正Gof23种设计模式之一的"抽象工厂"模式。
定义:
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
假设现在对象类型变得复杂横向纵向两个纬度都要扩展?如下图所示。
升级后的需求
按照老二工厂方法模式的思想。定义一个抽象工厂接口,每一个具体商品会实现对应的工厂类,那么就有了2*3=6种工厂类,如果在继续扩展工厂实现类会变得很多很繁杂,所以为了解决这种问题,我们在工厂方法模式上再抽象一层概念。
抽象工厂模式这样我们只需要两个具体工厂就能生产6种产品了。
//抽象产品——鞋子
public interface Shoes {
void displayShoes();
}
//抽象产品——裤子
public interface Pants {
void displayPants();
}
//抽象产品——衣服
public interface Clothes {
void displayClothes();
}
//具体产品——耐克鞋子
public class NikeShoes implements Shoes {
@Override
public void displayShoes() {
System.out.println("耐克鞋~~~");
}
}
//具体产品——耐克衣服
public class NikeClothes implements Clothes {
@Override
public void displayClothes() {
System.out.println("耐克衣服~~~");
}
}
//具体产品——耐克裤子
public class NikePants implements Pants {
@Override
public void displayPants() {
System.out.println("耐克裤子~~~");
}
}
//具体产品——阿迪鞋子
public class AdidasShoes implements Shoes {
@Override
public void displayShoes() {
System.out.println("阿迪达斯鞋子~~~");
}
}
//具体产品——阿迪衣服
public class AdidasClothes implements Clothes{
@Override
public void displayClothes() {
System.out.println("阿迪达斯衣服~~~");
}
}
//具体产品——阿迪裤子
public class AdidasPants implements Pants {
@Override
public void displayPants() {
System.out.println("阿迪达斯裤子~~~");
}
}
//抽象工厂
public interface AbstractFactory {
Shoes getShoes();
Clothes getClothes();
Pants getPants();
}
//耐克工厂
public class NikeFactory implements AbstractFactory {
@Override
public Shoes getShoes() {
return new NikeShoes();
}
@Override
public Clothes getClothes() {
return new NikeClothes();
}
@Override
public Pants getPants() {
return new NikePants();
}
}
//阿迪工厂
public class AdidasFactory implements AbstractFactory {
@Override
public Shoes getShoes() {
return new AdidasShoes();
}
@Override
public Clothes getClothes() {
return new AdidasClothes();
}
@Override
public Pants getPants() {
return new AdidasPants();
}
}
public class Shopping {
public static void main(String args[]) {
AbstractFactory nikeFactory = new NikeFactory();//可通过配置文件获得
Shoes nikeShoes = nikeFactory.getShoes();
nikeShoes.displayShoes();
Clothes nikeClothes = nikeFactory.getClothes();
nikeClothes.displayClothes();
AbstractFactory adidasFatory = new AdidasFactory();
Shoes adidasShoes = adidasFatory.getShoes();
adidasShoes.displayShoes();
Pants adidasPants = adidasFatory.getPants();
adidasPants.displayPants();
}
}
//输出
-------------------
//耐克鞋~~~
//耐克衣服~~~
//阿迪达斯鞋子~~~
//阿迪达斯裤子~~~
例子虽然简单,但是想要应用实际用的好还是需要多加练习的。越抽象的方法越难理解但应用越广泛。抽象工厂方法也有缺点。它不适合架构设计好后频繁修改,因为横向纵向都扩展了以后必然存在“牵一发而动全身”的影响。所以要想把设计模式应用的巧妙灵活,真的是一门需要慢慢修炼的“内功”
网友评论