당신은 여전히 잘못된 경우를 달성하기 위해 추상 팩토리 패턴을 참조?

추상 팩토리 패턴 검색의 어제와 구현에 대해 이야기 발견 꽤 많은 블로그 게시물과 내가 또한 어떤 과정을 볼 수 차이를 인식하지만, 여전히 1 위를 차지되는 검색 엔진의 말을 잘못된 것입니다.

우리는 문제가되지 않습니다 간단한 공장 패턴 및 공장 방법 패턴 이야기, 추상 팩토리 패턴의 핵심은 옳지 않다.

에 대해 얘기했다 얼마나 잘못된 참조 다음을 검토하는 간단한 공장 패턴과 팩토리 메소드 패턴으로 시작하고. 추상 팩토리 패턴을 암기 된이 문서를 무시하십시오.

간단한 공장 패턴 :

인터페이스, 각 특정 제품 클래스가이 인터페이스를 구현하는 방법을 정의에 대한 공통의 제품이있다, 그 다음 공장의 내부, 특히 제품의 클라이언트 인스턴스의 생산을위한 공장 클래스 호출되는 클래스 생산 제품 라인의 특별한 인스턴스가 ifelse 다른 특정 제품은 클라이언트로 반환 생성 어떤 특정 제품을 생성 할 때를 결정하기 위해 클라이언트에 의해 전달 된 다른 파라미터들에 의하면, 달성 된 스위치 또는 논리적 판단을 달성하는 것이다. 이러한 방법으로, 공장 클래스는 모든 제품의 논리적 통합을 만들기 위해, 그것은 핵심으로 전환하는 전지전능된다. 이 모든 새로운 제품 구현 클래스에서 제품 인터페이스, 팩토리 클래스가 어떤 시간에 결정하기 위해 제품을 만들기 위해 코드를 추가해야하는 클래스의 논리에 초점을 맞출 것이다 때문에 그러나 그것은 또한 자신의 단점을했다, 우리는 추가해야 새로운 결정 로직.

 ShoesFactory 공장

공공  클래스 ShoesFactory {
     공공  정적  최종 문자열 NIKE = "NIKE" ;
    공공  정적  최종 문자열 ADIDAS = "아디다스" ;
    공공  정적 신발 getShoes (문자열 브랜드) {
        신발 신발 = 널 (null) ;
        스위치 (브랜드) {
             경우 "NIKE" :
                신발 = 새로운 NikeShoes ();
                휴식 ;
            경우 "아디다스" :
                신발 = 새로운 AdidasShoes ();
                휴식 ;
            기본 :
                신발 = 널 (null) ;
        }
        반환 신발;
    }
}

 테스트 카테고리

공공  클래스 SimpleFactoryTest {
     공공  무효 메인 ([] 인수 문자열) {
        신발의 nikeShoes =의 ShoesFactory.getShoes (ShoesFactory.NIKE);
        nikeShoes.desc ();
        신발의 adidasShoes =의 ShoesFactory.getShoes (ShoesFactory.ADIDAS);
        adidasShoes.desc ();
    }
}

 

단점 : 각 추가 제품은 개방과 자바의 폐쇄의 원칙을 준수하지 않는 공장 클래스에 지점을 추가 한 후 새로운 클래스를 작성해야합니다.

장점 : 외부 차폐 제품의 인스턴스를 생성, 클라이언트가이 방법으로 책임의 분단을 달성하기 위해 "소비자"에 대해서만 책임이 있습니다.

공장 방법 패턴 :

제품 인터페이스와 공통의 제품 팩토리 인터페이스 공통가있다, 어떤 콘크리트 공장이 공장 인터페이스를 구현해야합니다. 특정 제품의 예로는 특정 식물의 종류, 공장의 하나의 의무 작업을 만들 것입니다, 각 제품 인스턴스가 공공 팩토리 클래스에서 꺼내 커플 링의 정도를 줄일 수 있습니다. 따라서, 때 새 제품 인스턴스, 단지 개방 및 폐쇄의 원칙에 맞춰, 적절한 클래스의 공장을 추가합니다.

 
ShoesFactory
공용  인터페이스 ShoesFactory {
    신발 getShoes ();
}

 NikeShoesFactory 

공공  클래스 NikeShoesFactory는 구현 ShoesFactory을 {
    @보수
    공공 신발 getShoes는 () {
         반환  ) (NikeShoes을;
    }
}

 AdidasShoesFactory 

공공  클래스 AdidasShoesFactory는 구현 ShoesFactory을 {
    @보수
    공공 신발 getShoes는 () {
         반환  ) (AdidasShoes을;
    }
}

 

리 닝 신발은 단순히 그것을 달성 한 다음이 LiningShoes 인스턴스의 생산에 대한 책임 ShoesFactory 있도록 인터페이스를 구현 LiningShoesFactory 팩토리 클래스를 높이기 위해 인터페이스 신발 LiningShoes을 추가하여 증가합니다.

단점 : 특정 제품의 증가는 팩토리 클래스에 상응하는 증가 수 없습니다 코드의 양을 늘려야합니다.

장점 : 개폐, 쉽게 확장의 원칙에 부합한다.

추상 팩토리 패턴 :

증가 된 바지, 상판, 및 기타 제품과 같은 제품의 여러 유형의 제품 유형 사이의 수평 개발이있을 때. 팩토리 메소드 패턴에서, 하나의 제품 인터페이스 신발의 종류, 나이키 신발, 아디다스 신발, 신발 인터페이스를 구현하고, 공장 클래스는 단지 라인에 두, 나이키 신발 공장, 아디다스 신발 공장 클래스, 각 클래스 공장 함수를 작성하는 등 모든 종류의 신발, 하나 하나의 특정 제품의 생산에 해당합니다.

한 번에 같은 바지, 자신의 특정 제품 아디다스 바지, 나이키 바지와 같은 제품의 새로운 유형의 증가, 이번에는 팩토리 클래스는 그것을 어떻게 달성 할 때? 또한 그 권리와 같은 팩토리 메소드를 좋아한다? 당신은 원칙적으로 사업에 단일 공장 (제품의 한 종류를 생산하는 공장)이 필요한 경우, 공장 출하 방법은 문제가되지 않습니다 계속 사용할 수 있지만, 팩토리 메소드 패턴을 사용하여 제품의 시리즈를 제공해야하는 경우 외관상으로는 충분하지 않습니다.

제품의 복수 종류의이 때 증가에서, 제품은 하나 개의 제품군 사이에 형성된, 제품의 다른 브랜드들 사이의 계층을 형성한다 (나이키 구두, 신발 아디는 제품군 나이키 팬티, 바지 아디는 제품군 인이다) .

원 총리의 네트워크 구현

내가 인터넷에서 추상 팩토리 패턴 []를 검색하고 발견했을 때 많은 기사 구현은이 같은 다음 그림에 나와있다.

추상 팩토리 패턴 구조 :

 

factory 包里放的是抽象工厂类和它的具体工厂类 PantsFactory 裤子工厂,ShoesFactory 鞋子工厂,而抽象工厂类里有两个方法 getPants 和 getShoes,所以对于这两个工厂来说,继承抽象工厂后都会有一个空的方法实现返回null,因为具体的工厂只生产某一产品,即裤子厂只生产裤子,归于鞋子是空实现。

 

代码实现

抽象工厂类

public abstract class AbstractFactory2{
    public abstract Shoes getShows(String brand);
    public abstract Pants getPants(String brand);
}

 PantsFactory 裤子工厂

public class PantsFactory extends AbstractFactory2{
    //裤子工厂不能生产鞋子,空实现 返回null
    @Override
    public Shoes getShows(String brand) {
        return null;
    }

    @Override
    public Pants getPants(String brand) {
        Pants pants = null;
        switch (brand) {
            case "NIKE":
                pants = new NikePants();
                break;
            case "ADIDAS":
                pants = new AdidasPants();
                break;
            default:
                pants = null;
        }
        return pants;
    }
}

 

ShoesFactory 鞋子工厂
public class ShoesFactory extends AbstractFactory2{
    @Override
    public Shoes getShows(String brand) {
        Shoes shoes = null;
        switch (brand) {
            case "NIKE":
                shoes = new NikeShoes();
                break;
            case "ADIDAS":
                shoes = new AdidasShoes();
                break;
            default:
                shoes = null;
        }
        return shoes;
    }
    //鞋子工厂不能生产鞋子,空实现 返回null
    @Override
    public Pants getPants(String brand) {
        return null;
    }
}

 

FactoryProductor2工厂生产者,通过不同的产品名称创建具体工厂实例:(这里貌似简单工厂模式)
public class FactoryProductor2{
    public static final String SHOES = "SHOES";
    public static final String PANTS = "PANTS";

    public static AbstractFactory2 getFactory(String productType) {
        if (SHOES.equalsIgnoreCase(productType)) {
            return new ShoesFactory();
        } else if (PANTS.equalsIgnoreCase(productType)) {
            return new PantsFactory();
        }
        return null;
    }
}

 测试类

public class AbstractFactoryTest2{
    public static void main(String[] args) {
        AbstractFactory2 factory = FactoryProductor2.getFactory(FactoryProductor2.PANTS);
        Pants nikePants = factory.getPants("NIKE");
        Pants adidasPants = factory.getPants("ADIDAS");
        nikePants.desc();
        adidasPants.desc();

        factory = FactoryProductor2.getFactory(FactoryProductor2.SHOES);
        Shoes nikeShoes = factory.getShows("NIKE");
        Shoes adidasShows = factory.getShows("ADIDAS");
        nikeShoes.desc();
        adidasShows.desc();
    }
}

 

NikePants
AdidasPants
NikeShoes
AdidasShoes

 

分析正确性

大家看这样的抽象工厂,每次创建产品都要知道产品的品牌,而且工厂类的另外一个方法被废弃。

还美名其曰的说产品族难扩展,产品等级易扩展。那我们就来看看在这种方式下是怎么个难易法。

产品族难扩展: 当我们想增加上衣Coat产品时,按现在的方式扩展一下看看。首先我们需要新建接口Coat,新建实现类NikeCoat和AdidasCoat实现Coat接口。然后我们需要在抽象工厂类增加创建Coat产品的方法,同时修改现有的2个工厂完成Coat相关实现类的实例创建逻辑,其次我们需要在FactoryProductor2增加分支逻辑创建CoatFactory。

撇开FactoryProductor2类不说,总结下我们都做了什么:

  • 新增产品接口Cost
  • 修改抽象工厂,新增getCoat方法,修改原有工厂增加getCoat的空实现
  • 新增具体工厂CoatFactory

产品等级易扩展: 当我们想增加李宁品牌时,我们需要做什么?pants包下创建LiNingPants实现pants接口,shoes包下创建LiNingShoes实现Shoes接口,然后修改factory包下的ShoesFactory工厂和PantsFactory工厂,各自增加分支判断创建李宁牌的鞋子和裤子。

总结下我们都做了什么:

  • 新增具体产品 LiNingPants 和 LiNingShoes

  • 修改现有具体工厂类 ShoesFactory 工厂和 PantsFactory 工厂,增加创建李宁工厂分支

这样看来产品族扩展起来确实难,而且不符合开闭原则,但产品等级扩展起来却也不容易,也不符合开闭原则。

大家发现没有,现在的抽象工厂的具体工厂内部是怎么实现的?还是使用switch或ifesle分支,不论扩展产品族还是产品等级都需要改具体工厂类,增加分支,都不符合开闭原则。这是正确的抽象工厂??

NO!!

这样实现抽象工厂模式的不仅仅是搜到的几篇博文,而且还有*鸟教程,搜索排第一:)

 

正确的抽象工厂

看下这个图,发现具体工厂的名字变了,分别为AdidasFactory和NikeFactory,可想而知,以品牌命名具体的工厂只创建本品牌下的所有产品。

代码实现

抽象工厂类

public abstract class AbstractFactory{
    public abstract Shoes getShows();
    public abstract Pants getPants();
}

这样,每一个具体的工厂类,实现具体方法时,每个方法都能生成对应的产品,方法没有空实现。而且每一个具体工厂内部没有判断分支。

NikeFactory耐克工厂

public class NikeFactory extends AbstractFactory{
    @Override
    public Shoes getShows() {
        return new NikeShoes();
    }
    @Override
    public Pants getPants() {
        return new NikePants();
    }
}

 

AdidasFactory阿迪工厂

public class AdidasFactory extends AbstractFactory{
    @Override
    public Shoes getShows() {
        return new AdidasShoes();
    }
    @Override
    public Pants getPants() {
        return new AdidasPants();
    }
}

 

而对于工厂生产者来说,通过不同的品牌名称创建对应的工厂实例,

public class FactoryProductor{
    public static final String NIKE = "NIKE";
    public static final String ADIDAS = "ADIDAS";

    public static AbstractFactory getFactory(String brand) {
        if (NIKE.equalsIgnoreCase(brand)) {
            return new NikeFactory();
        } else if (ADIDAS.equalsIgnoreCase(brand)) {
            return new AdidasFactory();
        }
        return null;
    }
}

 测试类

public class AbstractFactoryTest{
    public static void main(String[] args) {
        AbstractFactory nikeFactory = FactoryProductor.getFactory(FactoryProductor.NIKE);
        Pants nikePants = nikeFactory.getPants();
        Shoes nikeShows = nikeFactory.getShows();
        nikePants.desc();
        nikeShows.desc();

        AbstractFactory adidasFactory = FactoryProductor.getFactory(FactoryProductor.ADIDAS);
        Shoes adidasShows = adidasFactory.getShows();
        Pants adidasPants = adidasFactory.getPants();
        adidasPants.desc();
        adidasShows.desc();

    }
}
NikePants
NikeShoes
AdidasPants
AdidasShoes

分析

现在我们再来看一下,所谓的产品族难扩展,产品等级易扩展。

产品族难扩展: 当增加cost上衣产品时,首先需要新建包coat,新建接口Coat,新建实现类NikeCoat和AdidasCoat,然后在抽象工厂类新增抽象方法getCoat,ShoesFactory工厂和PantsFactory工厂分别实现该方法。

都做了什么:新建产品接口Coat,并创建实现类,抽象工厂新增抽象方法,原具体工厂类重写新增的抽象方法。

产品等级易扩展: 当增加新的品牌时,比如增加李宁牌的鞋子和裤子,怎么扩展?首先创建LiningShoes和LiningPants类分别实现Shoes和Pants接口,然后新建LiningFactory工厂类使其继承AbstractFactory抽象工厂类,重写getShoes和getPants方法。

都做了什么:新增产品实现类,新增具体工厂类。

类图

 

增加产品族

增加后,这个系统中有三个产品族,两个产品等级

增加产品等级

增加后,这个系统中2个产品族,3个产品等级

 


作者:walkinger
链接:https://juejin.im/post/5d4b8de1e51d453b1f37eac4


추천

출처www.cnblogs.com/ibigboy/p/11321837.html