工厂模式
工厂模式的定义
将对象的创建交由工厂进行获取,由工厂将对象转交给调用者。通过增加工厂角色,达到 对象的获取和对象的创建 解耦合。
工厂模式涉及到的四类角色分为:
- 抽象工厂:定义抽象方法,定义对产品对象的获取并返回
- 具体工厂:定义具体方法,实现对产品对象的获取并返回
- 抽象产品:定义抽象方法,定义对产品对象的创建
- 具体产品:定义具体方法,实现对产品对象的创建
工厂设计的实现主要分为三类:
- 简单工厂设计:角色分为:具体工厂、抽象产品、具体产品
- 工厂设计:角色分为:抽象工厂、具体工厂、抽象产品、具体产品
- 抽象工厂设计:角色分为:抽象工厂、具体工厂、抽象产品、具体产品
工厂模式的实现
1.简单工厂模式实现:
具体工厂类
public class FactoryImpl {
public AbstractProduct getProduct() {
return new AbstractProductImpl();
}
}
抽象产品类
public abstract class AbstractProduct {
public String name;
public abstract void setName();
}
具体产品类
public class AbstractProductImpl extends AbstractProduct {
@Override
public void setName() {
this.name="产品对象";
}
@Override
public String toString() {
return "AbstractProductImpl{" +
"name='" + name + '\'' +
'}';
}
}
对象的创建和调用
public class Shop {
public void sell(){
//获取工厂
FactoryImpl factory = new FactoryImpl();
//获取对象
AbstractProduct product = factory.getProduct();
System.out.println("购买产品"+product);
System.out.println("店家附带产品");
}
public static void main(String[] args) {
Shop shop = new Shop();
shop.sell();
}
}
结果
购买产品AbstractProductImpl{name='牛奶'}
店家附带产品
分析:该方式将对象的获取和创建通过工厂类进行了解耦,但是工厂类和调用者却是紧密相关,当换一家工厂生产时,必然需要修改调用方的代码,破坏了开闭原则。因此,为了满足开闭原则的要求,在具体工厂类的基础上抽象出抽象工厂,蜕变成工厂模式的实现。
2.工厂模式实现:
抽象工厂
public abstract class AbstractFactory {
public abstract AbstractProduct getProduct();
}
具体工厂
public class AbstractFactoryImpl extends AbstractFactory{
@Override
public AbstractProduct getProduct() {
AbstractProductImpl abstractProduct = new AbstractProductImpl();
abstractProduct.setName("牛奶");
return abstractProduct;
}
}
抽象产品和具体产品与简单工厂模式相同,在此不再赘述。
对象的创建和调用
public class Shop {
private AbstractFactory abstractFactory;
public void setAbstractFactory(AbstractFactory abstractFactory) {
this.abstractFactory = abstractFactory;
}
public void sell(){
//获取对象
AbstractProduct product = abstractFactory.getProduct();
System.out.println("购买产品"+product);
System.out.println("店家附带产品");
}
public static void main(String[] args) {
AbstractFactoryImpl abstractFactory = new AbstractFactoryImpl();
Shop shop = new Shop();
shop.setAbstractFactory(abstractFactory);
shop.sell();
}
}
分析:依据依赖倒转原则,对工厂的抽象进行依赖,解耦店家和工厂的直接关系,防止对开闭原则的破坏。
3.抽象工厂模式实现
抽象工厂模式的实现依据对工厂模式的改进,将工厂模式中仅对单一产品类进行生产改进为对多种单一产品同一级别产品的生产,即生产价位相同的不同种类商品。要实现这种模式,其实也是较为简单的,仅需要在抽象工厂类中添加新的抽象方法,由具体工厂类进行实现对新产品的获取。
抽象工厂类
public abstract class AbstractFactory {
public abstract AbstractProduct getProduct();
public abstract AbstractNewProduct getNewProduct();
}
具体工厂类
public class AbstractFactoryImpl extends AbstractFactory{
@Override
public AbstractProduct getProduct() {
AbstractProductImpl abstractProduct = new AbstractProductImpl();
abstractProduct.setName("牛奶");
return abstractProduct;
}
@Override
public AbstractNewProduct getNewProduct() {
AbstractNewProductImpl abstractProduct = new AbstractNewProductImpl();
abstractProduct.setName("咖啡");
return abstractProduct;
}
}
抽象产品和具体产品与简单工厂模式相同,在此不再赘述。(使用AbstractProductImpl和AbstractNewProductImpl表示两类产品)
对象的创建和调用
public class Shop {
private AbstractFactory abstractFactory;
public void setAbstractFactory(AbstractFactory abstractFactory) {
this.abstractFactory = abstractFactory;
}
public void sell(){
//获取对象
AbstractProduct product = abstractFactory.getProduct();
AbstractNewProduct newProduct = abstractFactory.getNewProduct();
System.out.println(String.format("购买产品%s和%s",product,newProduct));
System.out.println("店家附带产品");
}
public static void main(String[] args) {
AbstractFactoryImpl abstractFactory = new AbstractFactoryImpl();
Shop shop = new Shop();
shop.setAbstractFactory(abstractFactory);
shop.sell();
}
}
结果
购买产品AbstractProductImpl{name='牛奶'}和AbstractNewProductImpl{name='咖啡'}
店家附带产品
分析:抽象工厂模式实现了对多种产品的生产,但是仍然存在弊端,在想要添加新产品到工厂中时,需要在抽象工厂的子类实现中,实现该获取新产品的方法。
工厂模式的应用实例-集合中的迭代器
源码分析:
集合中,set和list的顶级接口是Collection,其中Collection是一个抽象工厂类,该接口继承了Iterable接口,提供了获取迭代器的抽象方法。
抽象工厂:
public interface Collection<E> extends Iterable<E>
Iterator<E> iterator();
具体工厂:以ArrayList为例,是Collection接口的具体实现
public Iterator<E> iterator() {
return new Itr();
}
具体产品是ArrayList内部实现类Itr对Iterator接口的实现。
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}