zoukankan      html  css  js  c++  java
  • 002-创建型-02-抽象工厂模式(Abstract Factory)

    一、概述

      抽象工厂模式提供同一个创建一系列相关或相互依赖对象的接口,无须指定它们具体的类  

      抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。

    1.1、使用场景

      客户端(应用层)不依赖于具体产品类实例如何被创建、实现等细节

      强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码

      提供一个产品类的库,所有的产品以同样的接口出现从而使客户端不依赖于具体实现

    1.2、优缺点

      优点:
        1.它分离了具体的类
        2.它使得易于交换产品系列
        3.它有利于产品的一致性
      缺点:
        难以支持新种类的产品,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码
        不容易扩展,也就是可扩展性不好,抽象工厂类一改,所有的具体工厂实现类都要变化。抽象工厂模式也会造成类层次过为复杂的情况。

      与工厂方法模式:抽象工厂模式创建的是产品族,工厂方法模式创建的是单个产品,二者的实现原理都是将创建类的过程延迟到子类。

      与单例模式:抽象工厂模式里的具体工厂实现通常在整个应用中只有一个实例,因此可以把具体的实现创建为单例。

    1.3、类图角色及其职责

      

       1、抽象工厂(Creator)角色:(FruitFactory)【AbstractFactory:抽象工厂,提供统一的接口工厂】
          是抽象工厂模式的核心,包含对多个产品结构的声明,任何工厂类都必须实现这个接口。
       2、具体工厂(Concrete Creator)角色:(NorthFactory、SouthFactory)【ConcreteFactory】
          这是实现抽象工厂接口的具体工厂类,负责实例化某个产品族中的产品对象。
       3、抽象产品(Product)角色:(Fruit)【AbstractProduct】
          抽象工厂模式所创建的对象的父类,它负责描述所有实例所共有的公共接口。
       4、具体产品(Concrete Product)角色:(Apple、Banana)
          抽象模式所创建的具体实例对象。
     
       抽象工厂中方法对应产品结构,具体工厂对应产品族。

    1.4、演进

      工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?

    示例

      首先确定我们的产品族,产品族为南方水果与北方水果,而水果(产品等级)有苹果和香蕉产品等级,所以具体产品为南方苹果,北方苹果,南方香蕉,北方香蕉。
      具体代码如下:首先每一个族中都有苹果和香蕉,所以定义两个抽象类,其中包含一个抽象方法

    基础类

    Fruit接口

    public interface Fruit {
        void get();
    } 

    苹果以及香蕉基础抽象类

    public abstract class Apple implements Fruit {
        public abstract void get();
    }
    public abstract class Banana implements Fruit{
        public abstract void get();
    }

    在写苹果香蕉的具体产品,并各自继承对应的抽象类

      北方苹果

    public class NorthApple extends Apple {
        @Override
        public void get() {
            System.out.println("采集北方苹果");
        }
    }

      南方苹果

    public class SouthApple extends Apple {
        @Override
        public void get() {
            System.out.println("采集南方苹果");
        }
    }

      北方香蕉

    public class NorthBanana extends Banana {
        @Override
        public void get() {
            System.out.println("采集北方香蕉");
        }
    }

      南方香蕉

    public class SouthBanana extends Banana {
        @Override
        public void get() {
            System.out.println("采集南方香蕉");
        }
    }

    接下来创建工厂,而每一个产品族都对应一个具体的工厂,每个产品族都包含苹果和香蕉,所以每个工厂中都包含苹果和香蕉

    抽象工厂

    public interface FruitFactory {
        //实例化一个苹果
        Fruit getApple();
    
        //实例化一个香蕉
        Fruit getBanana();
    } 

      北方工厂

    public class NorthFactory implements FruitFactory{
        @Override
        public Fruit getApple() {
            return new NorthApple();
        }
    
        @Override
        public Fruit getBanana() {
            return new NorthBanana();
        }
    }

      南方工厂

    public class SouthFactory implements FruitFactory{
        @Override
        public Fruit getApple() {
            return new SouthApple();
        }
    
        @Override
        public Fruit getBanana() {
            return new SouthBanana();
        }
    }

    测试

        @Test
        public void testFactory(){
            FruitFactory nf = new NorthFactory();
    
            Fruit nApple = nf.getApple();
            nApple.get();
    
            Fruit nBanana = nf.getBanana();
            nBanana.get();
    
            FruitFactory sf = new SouthFactory();
    
            Fruit sApple = sf.getApple();
            sApple.get();
    
            Fruit sBanana = sf.getBanana();
            sBanana.get();
        } 

    上述类图

      

      这时如果想新增一个产品族热带水果,只需新建一个热带产品族的工厂即可,已经建好的南方与北方工厂无需改动,也符合开放-封闭原则。

      但缺点也很明显,从产品等级来看,如果想新增一个产品等级,例如上面的例子只有苹果与香蕉,如果现在新增一个葡萄,就需要在抽象工厂中添加一个葡萄抽象方法,再在每一个具体工厂中实现此方法。这样就完全不符合开放-封闭原则了。

     二、扩展

    java.sql.Connection

    java.sql.Statement

    sqlsessionfactory

  • 相关阅读:
    javascript 原型世界浅析
    zookeeper
    Message Queue
    js给对象onclick事件赋值
    什么是堡垒机
    什么是数据库实例
    动态规划解决矩阵路径问题
    0-1背包问题
    回溯算法
    Python列表的复制
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11133289.html
Copyright © 2011-2022 走看看