设计模式(二 & 三)工厂模式:3-抽象工厂模式

  •  什么是抽象工厂?

  抽象工厂模式,引入了“产品族”的概念。

  何为产品族?还是以 设计模式(二)工厂模式:2-工厂方法模式 提到的 Operation 为例。

  之前讨论的都是局限于 Operation 这个产品,这是一个由“工厂”做出来的产品,而至于是哪一个工厂做出来的产品,我们并不关心。

  抽象工厂模式关注的就是这一点,现在为其加上前缀:“工厂1生产的 Operation”,“工厂2生产的 Operation”。

  这就是产品族,对象拥有相同的行为,但却是有不同的实现。

 

  • 模拟场景:

   Operation 在这个并不能很好地体现 抽象工厂 的优势,我们换一个例子:

  现在,我需要去创建用户(User)和部门(Department)两个对象,但是底层需要用的数据库(DB2 和 MySQL),可能产生变化,所以需要两套解决方案。

 

  • 思想:

  首先,针对需要创建的对象,需要一个抽象工厂(AbsFactory),负责创建抽象用户(AbsUser)和抽象部门(AbsDepartment)。

  根据底层的数据库,抽象工厂拥有两个实现,DB2 工厂(FactoryDB2)和 MySQL 工厂(FactoryMySQL)。

  每个工厂各司其职,创建对应的继承抽象类的对象。

 

  • UML

  

 

  • UML 分析:

  这是一个针对给出情景的完整 UML 类图。

  为用户(AbsUser)定义了两种行为,而部门(AbsDepartment)没有定义行为。

  从 UML 就可以看出,抽象工厂,是对 工厂方法 的一种延伸,FactoryDB2 和 FactoryMySQL 起着 AbsOperationFactory 的作用。

  将工厂方法的 AbsOperationFactory 转为实例工厂,并在之上加上一个抽象层,就是抽象工厂。

 

  • 代码:
public abstract class AbsFactory {

    public abstract AbsUser createUser();

    public abstract AbsDepartment createDepartment();
}
public final class FactoryDB2 extends AbsFactory {

    @Override
    public UserDB2 createUser() {
        return new UserDB2();
    }

    @Override
    public DepartmentDB2 createDepartment() {
        return new DepartmentDB2();
    }
}
public final class FactoryMySQL extends AbsFactory {

    @Override
    public UserMySQL createUser() {
        return new UserMySQL();
    }

    @Override
    public DepartmentMySQL createDepartment() {
        return new DepartmentMySQL();
    }
}

 

public abstract class AbsUser {

    protected boolean hasRegistered = false;

    protected void joinDepartment(AbsDepartment department) {
        if (hasRegistered) {
            System.out.println(this + " join " + department);
        } else {
            System.out.println(this + " not registered cannot join department");
        }
    }

    protected abstract void register();

    @Override
    public String toString() {
        return "User[" + this.getClass().getSimpleName() + ":" + this.hashCode() + "]";
    }
}
public final class UserDB2 extends AbsUser {

    @Override
    public void register() {
        super.hasRegistered = true;
        System.out.println(this + "register success");
    }
}
public final class UserMySQL extends AbsUser {

    @Override
    public void register() {
        super.hasRegistered = false;
        System.out.println(this + "register failure");
    }
}

 

public abstract class AbsDepartment {

    @Override
    public String toString() {
        return "Department[" + this.getClass().getSimpleName() + ":" + this.hashCode() + "]";
    }
}
public final class DepartmentDB2 extends AbsDepartment {

}
public final class DepartmentMySQL extends AbsDepartment {

}

 

  • 客户端的调用代码:
public final class AbsFactoryTest {

    @Test
    void testFactoryDB2() {
        AbsFactory factory = new FactoryDB2();
        AbsUser user = factory.createUser();
        AbsDepartment department = factory.createDepartment();
        user.register();
        user.joinDepartment(department);
    }

    @Test
    void testFactoryMySQL() {
        AbsFactory factory = new FactoryMySQL();
        AbsUser user = factory.createUser();
        AbsDepartment department = factory.createDepartment();
        user.register();
        user.joinDepartment(department);
    }
}

 

  • 优势

  从客户端的调用,我们就可以发现,从创建用户开始,后续的代码都是一致的。

  也就是说,只需要改变顶层的实例工厂,就可以改变具体的行为(到底是 MySQL 还是 DB2)。

  如果需要加入新的工厂,例如 FactoryOracle,不会对现有的代码产生破坏,很好体现了:对扩展开放,对修改关闭。

 

  • 劣势

  在设计 抽象工厂 时,需要完整地考虑到工厂需要创建哪些东西,在这个例子上就是 User 和 Department。

  如果在设计完毕之后,需要引入新的产品,例如订单 Order 之类的,对于现有代码的结构破坏会很大,从顶层开始就破坏了代码的封装性。

 

  • 抽象工厂有哪些实际应用?

  数据库的 ORM 框架。

  Java 平台无关的特性。

 

posted @ 2017-09-18 17:46  Gerrard_Feng  阅读(256)  评论(0编辑  收藏  举报