设计模式--工厂模式 (工厂方法、简单工厂、抽象工厂)

设计模式--工厂模式 (工厂方法、简单工厂、抽象工厂)

    工厂方法模式:定义一个用于创建对象的接口,让子类来决定实例化那一个类。工厂方法使一个类的实例化延迟到其子类。

       在了解工厂方法前,我们要先了解什么是工厂。现实生活中工厂是生产产品的地方,我们身边的电脑、鼠标、电视等等,都是从各个工厂生产出来的。


    如果你对这个图看不明白,那么我们一步步来解释。

 ----------------------------------------------简单工厂-------------------------------------------------------------------------

  

  就拿我们面前的电脑来说,电脑可以上网。如果只是一台电脑,我们建立一个类就行了,当用到的时候就创建一台电脑就行了。


public class 台式机电脑 {   
 //上网方法
    public void 上网(){
        System.out.println("浏览网页");
    }
}
 
public class 电脑测试 {
    public static void main(String[] args) {
        //创建电脑
台式机电脑 我的电脑 = new 台式机电脑();
        我的电脑.上网();
    }
}

     如果有一天电脑公司要生产笔记本电脑了、

   平板电脑、超级本了,这时就需要建立一个工厂,让工厂来完成电脑的创建。

   先看看代码:

public class 电脑工厂 {
    public 台式机电脑 制造台式机(){
//       返回一台新的台式机电脑
        return new 台式机电脑();
    }
    public 笔记本电脑 制造笔记本电脑(){
//      返回一台新的笔记本电脑
        return new 笔记本电脑();
    }
    public 平板电脑 制造平板电脑(){
//      返回一台新的平板电脑
        return new 平板电脑();
    }
    public 超级本电脑 制造超级本电脑(){
//      返回一台新的笔记本电脑
        return new 超级本电脑();
    }
}
 
public class 台式机电脑 {
    public void 上网(){
        System.out.println("浏览网页");
    }
}
 
public class 笔记本电脑 {
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}
 
public class 超级本电脑 {
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}
 
public class 平板电脑 {
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}
 
public class 电脑测试 {
    public static void main(String[] args) {
        台式机电脑 台式机 = new 台式机电脑();
        台式机.上网();
        笔记本电脑 笔记本 = new 笔记本电脑();
        笔记本.上网();
        平板电脑  平板   = new 平板电脑();
        平板.上网();
        超级本电脑 超级本 = new 超级本电脑();
        超级本.上网();
    }
}
 

我们看到,这样做后,创建太麻烦了,我们应该把这些变化封装起来,让用户调用的时候,只需要根据需要让工厂创建就行

先创建一个电脑工厂:

 

public class 电脑工厂 {
    public 电脑 制造电脑(String 电脑类型){
        if(电脑类型.equals("台式机电脑")){
            return new 台式机电脑();
        }else if(电脑类型.equals("笔记本电脑")){
            return new 笔记本电脑();
        }else if(电脑类型.equals("平板电脑")){
            return new 笔记本电脑();
        }else if(电脑类型.equals("超级本电脑")){
            return new 笔记本电脑();
        }else{
            return null;
        }
    }
}
 

电脑工厂根据有一个制造电脑的方法,根据传入的电脑类型创建

然后抽象一个电脑接口,所有类型的电脑都实现这个电脑接口;

 

public interface 电脑 {
    public void 上网();
}

 

public class 笔记本电脑  implements 电脑{
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}


public class 超级本电脑  implements 电脑{
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}


public class 台式机电脑 implements 电脑{
    public void 上网(){
        System.out.println("浏览网页");
    }
}


public class 平板电脑  implements 电脑{
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}
 

 

public class 电脑测试 {
    public static void main(String[] args) {
        电脑工厂 工厂 = new 电脑工厂();
        电脑 台式机 = 工厂.制造电脑("台式机电脑");
        台式机.上网();
        电脑 笔记本 = 工厂.制造电脑("笔记本电脑");
        笔记本.上网();
        电脑  平板   = 工厂.制造电脑("平板电脑");
        平板.上网();
        电脑 超级本  = 工厂.制造电脑("超级本电脑");
        超级本.上网();
    }
}
 

 

再看看类图;


 

        【简单工厂】这种模式叫简单工厂模式,它先创建一个产品接口,然后让所有具体产品实现它,然后创建一个产品工厂,在产品工厂中有一个创建产品的方法,在创建产品的方法里,通过传入的产品名称,来返回具体的产品。

工厂方法适用产品比较固定的情况下,也就是产品不会增加或者减少。

如果产品系列可能发生变化,就不适合简单工厂模式了。

       

 ----------------------------------------------工厂方法-------------------------------------------------------------------------

如果现在电脑工厂开始生产上网本了,那么,是不是让上网本来实现电脑接口,然后在电脑工厂的创建电脑方法中去修改判断语句呢?

         这样就违反面向对象的设计原则—--对修改关闭,对扩展开放。

         【对修改关闭,对扩展开发】指的是程序设计时,应该考虑到变化,并将变化的部分给出接口,当新的变化需求来了后,只需要扩展系统的功能就行了,不需要去修改原有代码。只有遵循这样的设计,才能算是优秀的设计。

         如何应对产品线的变化呢?工厂方法就是解决这一问题的关键!让我们回头看看工厂方法的类图,然后想想我们如何设计电脑公司产品线!

  先看看类图:

 

public interface 电脑 {
    public void 上网();
}

 

 

public interface 电脑工厂 {
    public 电脑 制造电脑();
}
 

 

public class 台式机电脑 implements 电脑{
    public void 上网(){
        System.out.println("浏览网页");
    }
}
 

 

public class 上网本电脑  implements 电脑{
    public void 上网() {
        System.out.println("浏览网页"); 
    }
}
 

 

public class 台式机工厂  implements 电脑工厂{
    public 电脑 制造电脑() {
        return new 台式机电脑();
    }
}

 

 

public class 上网本工厂  implements 电脑工厂{
    public 电脑 制造电脑() {
        return new 上网本电脑();
    }
}
 

 

public class 电脑测试 {
    public static void main(String[] args) {
        电脑工厂 台式机工厂 = new 台式机工厂();
        电脑 台式机 = 台式机工厂.制造电脑();
        台式机.上网();
        
        电脑工厂 上网本工厂 = new 上网本工厂();
        电脑 上网本 =  上网本工厂.制造电脑();
        上网本.上网();
    }
}
 

 

     根据上面的类图和代码,我们再想想,如果再增加一个电脑类型,那么,不需要去修改任何代码,只需要在原有的基础上扩展代码就行了。我们只需要建立一个新电脑类型的工厂,建一个实现了电脑的产品类。就可以了,然后告诉用户,我们有这个产品了,你买的话,我就让工厂给你制造。是不是很简单!

         【工厂方法模式】 定义了制造具体产品的接口,然后让子类的具体产品工厂在自己的方法中创建具体的产品。工厂的方法让产品的创建延迟到子类的具体产品工厂中执行。

工厂方法模式适合产品变化的情况,如果产品会发生变化,使用工厂方法模式可以应对这种变化。

但是,如果有多条产品线(产品族),而且产品线或者产品类型会经常变化,那么就不能用工厂方法模式了。

        

 ----------------------------------------------抽象工厂-------------------------------------------------------------------------

随着时间的推移,电脑公司的发展越来越大,开始考虑多产品线、精细化发展,电脑公司董事会决定制造手机了!而且装备自己建配件厂,生产外壳的工厂和生产主板的工厂负责各自的产品,然后根据不同的需求送到具体产品工厂去生产产品,这样有利于控制成本和管理。可是新的问题来了,产品工厂与外壳、主板这些配件工厂如何关联呢?

         这就要用抽象工厂来处理了。

         【抽象工厂】提供一个创建一系列相关相互依赖对象的接口,而无需指定他们具体类。

         产品工厂都有一个配件装配流程,流程中的配件都是大体相同的,就点子产品来讲,都会从装主板、显示屏、装外壳这个流程来走,因为这个流程中的主板就是电路板,只有专业的电路板工厂才能制造出来,不能与制造外壳的工厂放到一起,因为技术含量和原料都不同,也不能把手机主板和电脑主板分开,因为这样就不能体现出资源的整合,成本、技术、人才的控制了。所以对于产品工厂来讲,声明装配主板、外壳这个流程中需要(依赖)的对象(外壳、主板),不需要指定具体那个产品类型的产品。当用户的产品那一天发生变化的时候,只需要让用户可以自动配置具体用那个类型的产品。


 

 

 

 


 

代码:

 

//主板接口
public interface 主板 {
}
 

 

//手机主板
public class 手机主板  implements 主板{
    public void 检测(){
        System.out.println("检测手机主板成功");
    } 
}

 //电脑主板

public class 电脑主板 implements 主板{
    public void 检测(){
        System.out.println("检测电脑主板成功");
    } 
}
 

 

//外壳接口
public interface 外壳 {
}
 

 

//手机外壳
public class 手机外壳  implements 外壳{
    public void 检测(){
        System.out.println("检测手机外壳成功");
    } 
}
 

 

//电脑外壳
public class 电脑外壳  implements 外壳{
    public void 检测() {
        System.out.println("检测电脑外壳成功"); 
    }
}

 

 

//主板接口
public interface 产品工厂 {
    主板 装主板();
    外壳 装外壳();
}
 

 

//手机工厂
public class 手机工厂 implements 产品工厂 {
    public 主板 装主板() {
        return new 手机主板();
    }
    public 外壳 装外壳() {
        return new 手机外壳();
    }
}
 

 

//电脑工厂
public class 电脑工厂 implements 产品工厂{
    public 主板 装主板() {
        return new 电脑主板();
    }
    public 外壳 装外壳() {
        return new 电脑外壳();
    }
}
 

 

//手机类
public class 手机 {
    private 外壳 手机外壳;
    private 主板 手机主板;
    public void 显示(){
        System.out.println("手机做好了,配件有:"+
this.手机主板 + "," + this.手机外壳);
    }
    // getter  &  setter
    public 外壳 get手机外壳() {
        return 手机外壳;
    }
    public void set手机外壳(外壳 手机外壳) {
        this.手机外壳 = 手机外壳;
    }
    public 主板 get手机主板() {
        return 手机主板;
    }
    public void set手机主板(主板 手机主板) {
        this.手机主板 = 手机主板;
    }
}
 

 

public class 产品测试 {
    public static void main(String[] args) {
        手机 我的手机 = new 手机();
        手机工厂 我的手机工厂 = new 手机工厂();
        主板 手机主板 = 我的手机工厂.装主板();
        外壳 手机外壳 = 我的手机工厂.装外壳();
        我的手机.set手机主板(手机主板);
        我的手机.set手机外壳(手机外壳);
        我的手机.显示();
    }
}
 

    这样的设计最大的好处是易于交换产品系列,比如那天手机主板或者外壳有变化,我们不需要去修改原有代码,只要通过实现主板或者外壳接口,然后在用户调用时传入新添加的主板或者外壳就可以解决问题。在一个应用中只需要在初始化的石化出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。这中模式就是让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂实现分离,不会出现在客户端代码中了。

就像下面的服饰代码,当我们出门时,需要搭配服饰,那么男人和女人会有不同风格的衣服,但是产品系列是一样的,比如上衣,比如裤子,在配衣服的时候不需要去关心具体用什么上衣,只关心某种风格的、或者某种性别的衣服搭配,不需要指定具体衣服。上衣类型增加或者减少都不会影响衣服的搭配。

    如果那天觉得男装或者女装不能满足需求,需要添加另外的类型,比如中性服装,这样就可以不修改代码的情况下解决问题:只需要继承服饰类,然后配各种上衣或者裤子就可以了。

    是不是超级灵活!

 

 


 

 

 

 

 

 

 

猜你喜欢

转载自chwshuang.iteye.com/blog/1629350