关于设计模式:设计模式之工厂方法和抽象工厂

5次阅读

共计 6446 个字符,预计需要花费 17 分钟才能阅读完成。

全网最具体的工厂设计模式,本文次要是创立型设计模式中的工厂办法和形象工厂,先由传统实现形式引出问题,接着对代码改良到简略工厂,后扩大到工厂办法,最初是形象工厂模式,文中包含概念了解和相干实现代码。

读者能够拉取残缺代码本地学习,实现代码均测试通过上传到码云

一、引出问题

如果有一个客户老王,须要购买产品,产品别离是 A、B、C。

如果用传统办法实现,别离定义 A、B、C 三个类,再别离创立他们所属的办法。

在客户对象中再别离调用他们的办法。

Product ClientProduct(String orderType) {
    Product product;

    if (orderType.equals("A")) {product = new ProductA();
    } else if (orderType.equals("B")) {product = new ProductB();
    } else if (orderType.equals("B")) {product = new ProductC();
    }
    
    // product 制作过程
    product.common();
    
    return product;
}

如果咱们须要再减少一个产品 D,就须要判断再减少一个分支,而后在分支外面创立产品对象,调用产品 D 的办法。

这样代码的维护性是极差的,查看咱们的软件设计七大准则,很显著,这违反了开闭准则、依赖倒置准则.

如果又有个客户小王,那么小王也必须依赖每个产品类,这样就显得繁杂。

二、简略工厂(动态工厂)

简略工厂(动态工厂)模式就利用而生了。

如果咱们将产品 A、B、C 形象进去一个父类,再专门创立一个工厂类,在客户购买产品时,只须要传入产品的类型,由工厂去创立产品。

简略工厂模式中蕴含如下角色:

Factory:工厂角色

​ 工厂角色负责实现创立所有实例的外部逻辑。

Product:形象产品角色

​ 形象产品角色是所创立的所有对象的父类,负责形容所有实例所共有的公共接口。

ConcreteProduct:具体产品角色

​ 具体产品角色是创立指标,所有创立的对象都充当这个角色的某个具体类的实例。

看看咱们对原始实现形式后的代码。

产品形象父类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Product {public void common(){System.out.println("这是产品父类公共办法...");
    }


}

产品 A:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ProductA extends Product{public void common(){System.out.println("这是产品 A 办法...");
    }

}

产品 B:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ProductB extends Product{public void common(){System.out.println("这是产品 B 办法...");
    }
}

工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */

public class SimpleFactory {public Product createProduct(String orderType) {
        Product product = null;

        if (orderType.equals("A")) {product = new ProductA();
        } else if (orderType.equals("B")) {product = new ProductB();
        } else if (orderType.equals("C")) {product = new ProductC();
        }
        return product;
    }
}

客户老王类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {

    SimpleFactory simpleFactory;

    public Client(SimpleFactory simpleFactory) {this.simpleFactory = simpleFactory;}

    public Product orderProduct(String orderType) {

        Product product;    

        product = simpleFactory.createProduct(orderType);

       // 调用每个产出相应的办法
        product.common();
        System.out.println(product.getClass());
        return product;
    }

    public static void main(String[] args) {Client client=new Client(new SimpleFactory());
        client.orderProduct("A");
    }

}

这样简略工厂模式就实现了,这样的话老王和具体的产品就很好的解耦了,也不须要老王再依赖具体产品类,依赖倒置问题就很好的解决了。

如果减少一个产品 D,须要再从新定义一个 D 类,实现 product 接口,而后在工厂类中减少一个分支构造。

不言而喻这样实现,缺点仍然存在:

1、工厂类集中了所有产品创立逻辑,职责过重,一旦产生异样,整个零碎将受影响。

    2、应用简略工厂模式将会减少零碎中类的个数,在肯定程序上减少了零碎的复杂度和了解难度。3、零碎扩大艰难,一旦减少新产品不得不批改工厂逻辑,在产品类型较多时,可能造成逻辑过于简单。4、简略工厂模式因为应用了动态工厂办法,造成工厂角色无奈造成基于继承的等级构造。

这种办法只是一种编码方式,并不输出设计模式的一种,且局限于产品种类较少。

三、工厂办法

在简略工厂中老王须要具体的产品,就在他本人的类中去创立须要的产品,老王尽管不依赖具体产品,但老王当初须要依赖工厂实现类了。

简略工厂是将产品类抽象化,具体的产品由工厂类去实现。

如果咱们将工厂类也抽象化,那就引出了咱们明天第一个设计模式——工厂办法。

工厂办法有四个角色:

1、形象工厂(Abstract Factory):提供了创立产品的接口,调用者通过它拜访具体工厂的工厂办法 createProduct() 来创立产品。

   2、具体工厂(ConcreteFactory):次要是实现形象工厂中的形象办法,实现具体产品的创立。3、形象产品(Product):定义了产品的标准,形容了产品的次要个性和性能。4、具体产品(ConcreteProduct):实现了形象产品角色所定义的接口,由具体工厂来创立,它同具体工厂之间一一对应。

咱们对简略工厂代码进行革新。

形象产品父类、产品 A 类、产品 B 类放弃不变。重点看工厂类

形象工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */

public abstract class AbstractFactory {public abstract Product createProduct(String orderType);
}

具体实现工厂 A 类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreteFactoryA extends AbstractFactory{
    @Override
    public Product createProduct(String orderType) {System.out.println("参数为:"+orderType);
        return new ProductA();}
}

具体实现工厂 B 类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreteFactoryB extends AbstractFactory{
    @Override
    public Product createProduct(String orderType) {return new ProductB();
    }
}

老王类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {

    AbstractFactory simpleFactory;

    public Client(AbstractFactory simpleFactory) {this.simpleFactory = simpleFactory;}

    public Product orderProduct(String orderType) {

        Product product;

        product = simpleFactory.createProduct(orderType);

       // 调用每个产出相应的办法
        product.common();
        System.out.println(product.getClass());
        return product;
    }

    public static void main(String[] args) {Client client=new Client(new ConcreteFactoryA());
        client.orderProduct("A");
    }

}

这样的益处就在于老王只管他要关注的形象工厂,具体是哪个工厂实现类生产产品,老王也不须要关注。

典型的解耦框架。高层模块只须要晓得产品的抽象类,毋庸关怀其余实现类,满足迪米特法令、依赖倒置准则和里氏替换准则。

毛病也是不言而喻的:

  • 类的个数容易过多,减少复杂度。
  • 思考到零碎的可扩展性,须要引入形象层,在客户端代码中均应用形象层进行定义,减少了零碎的抽象性和了解难度。
  • 形象产品只能生产一种产品。

如果对工厂办法仍然只知其一; 不知其二的话,接着往下看工厂办法的一个典型实现

在 JDK 中对工厂办法有大量的使用,其中比拟典型的是

new ArrayList<>().iterator();

咱们晓得汇合的一个大分支依赖的是 Collection 接口,咱们以 ArrayList 作为举例。

Collection 接口相当于产品的形象父类,ArrayList 相当于具体产品。

Iterator 是一个形象工厂,在 ArrayList 中有一个 Itr 外部类实现了 Iterator 接口

当咱们调用汇合的 iterator()办法遍历对象时,就会调用各自类的具体实现办法。

四、形象工厂

有一天,产品 A、B、C 降级革新了,三种产品别离有红色和蓝色,如果还用工厂办法的话,那几乎是个劫难,具体工厂实现类须要六个。

就引出咱们明天的第二个设计模式——形象工厂。

形象工厂模式(Abstract Factory Pattern):提供一个接口,用于创立创立一系列相干或相互依赖对象的家族,而无须指定它们具体的类。形象工厂模式又称为 Kit 模式,属于对象创立型模式。

形象工厂模式与工厂办法模式区别在于,工厂办法模式针对的是一个产品等级构造。

而形象工厂模式则须要面对多个产品等级构造(各种色彩),一个工厂等级构造能够负责多个不同产品等级构造(不同色彩)中的产品对象的创立。

形象工厂仍然是四个角色:

  • AbstractFactory:形象工厂
  • ConcreteFactory:具体工厂
  • AbstractProduct:形象产品
  • Product:具体产品

咱们开始革新工厂办法代码,既然是要把产品都分成一组,那理当把产品 A、B、C 都形象进去,再让工厂类去实现各个产品的不同色彩,也就是概念中的——用于创立创立一系列相干或相互依赖对象的家族。

接口看革新后的代码:

产品抽象类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public interface Product {public void common();

}

产品形象 A 家族类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class ProductA implements Product {public abstract void common();

}

产品形象 B 家族类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class ProductB implements Product {public abstract void common();
}

具体红色产品 A 类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class RedProductA extends ProductA{
    @Override
    public void common() {System.out.println("这是红色的产品 A");
    }
}

具体蓝色产品 A 类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class BlueProductA extends ProductA {

    @Override
    public void common() {System.out.println("这是蓝色的产品 A");
    }
}

形象 A 家族工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */

public interface AbstractProductFactory {public ProductA createProduct(String orderType);
}

实现 A 家族工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreateProductAFactory implements AbstractProductFactory{

    @Override
    public ProductA createProduct(String orderType) {return new BlueProductA();
    }
}

老王类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {

    ConcreateProductAFactory simpleFactory;

    public Client(ConcreateProductAFactory simpleFactory) {this.simpleFactory = simpleFactory;}

    public ProductA orderProduct(String orderType) {

        ProductA product;

        product = simpleFactory.createProduct(orderType);

       // 调用每个产出相应的办法
        product.common();
        System.out.println(product.getClass());
        return product;
    }

    public static void main(String[] args) {Client client=new Client(new ConcreateProductAFactory());
        client.orderProduct("A");
    }

}

这样的话,每天工厂类能够把 A 的产品家族类(红、蓝)都实现,形象工厂模式隔离了具体类的生成,使得老王并不需要晓得什么产品被创立,从具体的产品 解耦 进去。

  • 当一个产品族中的多个对象被设计成一起工作时,它可能保障客户端始终只应用同一个产品族中的对象。

如果要减少新产品、和新工厂很容易,如果再减少一个等级(色彩)代码批改起来就很苦楚了。

形象工厂模式在 Spring 中有大量的使用。

比拟典型的是,BeanFactory 是用于治理 Bean 的一个工厂,所有工厂都是 BeanFactory 的子类。这样咱们能够通过 IOC 容器来治理拜访 Bean,依据不同的策略调用 getBean() 办法,从而取得具体对象。

BeanFactory 的子类次要有

ClassPathXmlApplicationContext、

XmlWebApplicationContext、

StaticWebApplicationContext、

StaticApplicationContext。

在 Spring 中,DefaultListableBeanFactory 实现了所有工厂的公共逻辑。

正文完
 0