zoukankan      html  css  js  c++  java
  • 工厂模式

    简介

    工厂模式是java中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同接口来指向新创建的对象,其意思是代码编写出来是为了给别人调用的:

    • 调用者跟代码编写者可能是同一个人,也可能是不同人
    • 提供给调用者的代码,有可能是源码可见的,也可能是源码不可见、不可修改的(比如jar包)

    所以,为了简化代码的协作使用及管理维护,必须想尽办法简化代码逻辑,实现必要的分离。

    1、最原始的方式

    比如说,创建不同品牌的手机

    // 苹果品牌手机类
    public class Iphone {
        public void xxx () {
            System.out.println("我是苹果手机");
        }
    }
    
    //华为品牌手机类
    public class Huawei {
        public void yyy () {
            System.out.println("我是华为手机");
        }
    }
    
    .......

    如果这样的代码提供给客户端调用,那么提供者必须要将所有类的名称以及对应方法暴露给客户端。

    客户端的调试如下:

    Iphone phone1 = new Iphone();
    phone1.xxx();        // 输出:我是苹果手机
    
    Huawei phone2 = new Huawei();
    phone2.yyy();        // 输出:我是华为手机

    这样的方式非常原始,也很简单,但是代码逻辑不清晰,暴露的内容过多。

    解决的方案:

    • 抽象逻辑,提供接口
    • 2、有了接口之后

    为了减少方法调用的复杂度,也为了便于抽象跟代码管理,提供一个接口:

    public interface Phone {
        void play();
    }

    然后,将所有手机类都实现Phone接口,将暴露给客户端调用的逻辑都封装在play方法里;

    public class Iphone implements Phone{
    
      @Override
      public void play() {
          System.out.println("苹果手机");
      }
    }

    ......

    那么客户端需要知道的调用API就减少到了两种:

    1. Phone接口的信息
    2. Phone接口有哪些实现类
    Phone phone = new Iphone();
    phone.play();
    phone=new Huawei(); phone.play();

    这种方式有缺点:

    1. 客户端,必须要知道手机类的具体名字
    2. 客户端的调用,跟提供的代码是耦合的(服务端代码的更改,客户端的代码也要跟着改,比如:我们将IPhone类改为IPhonex,那么客户端那边也要跟着改)

    所以,自然产生了简单工厂的这种策略

    3、简单工厂

    在中间加一层:

    public class PhoneFactory {
        public Phone createPhone(String tag) {
            if (tag.equals("pg")) {
                return new IPhone();
            } else if (tag.equals("hw")) {
                return new Huawei();
            }else {
                return null;
            }
        }
    }

    客户端的调用

    PhoneFactory pf = new PhoneFactory();
    pf.createPhone("hw").play();
    pf.createPhone("pg").play();

    简单工厂模式,本身已经为解耦合做出来很好的方案。但是它有缺点:

    • PhoneFactory  代码跟Phone代码紧耦合
    • 每次添加/删除/修改某一个Phone ,都需要修改PhoneFactory这个类

    解决方案就是工厂方法模式

    4、工厂方法模式

    为Phone工厂,创建一个接口:

    public interface PhoneFactory {
        Phone createPhone();
    }

    如果增加了一款产品,比如是iPone,那么,只需要为iPhone创建一个工厂类就可以了

    public class IphoneFactory implements PhoneFactory {
        public phone createPhone() {
            return new IphoneX();
        }
    }
    如果再增加另外一款产品,比如Huawei,那么只需要另外一个工厂就可以了
    public class HuaweiFactory implements PhoneFactory {
        public phone createPhone() {
            return new Huawei();
        }
    }
    客户端的调用:
    PhoneFactory hwPf = new HuaweiFactory();
    hwPf.createPhone().play();
    
    PhoneFactory pgPf = new IphoneFactory();
    pgPf.createPhone().play();

    工厂方法模式,是最标准的一种工厂模式,也是应用广泛的一种模式。

    但是工厂方法模式,有一个很大的缺点:

    • 代码容易膨胀
    • 不容易反映产品与产品之间的关系

    5、抽象工厂

    public interface PhoneFactory {
        Phone createPhone();
        Usb createUSB();
        Charger createCharger();
    }

    华为手机:

    public class HuaweiPhoneFactory implements PhoneFactory {
        Phone createPhone() {
            return new HuaweiPhone();
        }
        Usb createUSB() {
            return new HuaweiUSB();
        }
        Charger createCharger() {
            return new HuaweiCharger();
        }
    }
    
    // ...
    客户端调用:
    PhoneFactory pf = new HuaweiPhoneFactory();
    pf.createPhone();
    pf.createUsb();
    pf.createCharger();
    
    // 通过一个工厂,把一个族中的相关产品全都输出来了
     
  • 相关阅读:
    【面霸2】
    【面霸1】php知识点
    【技术宅11】php入门运算
    【技术宅10】顺序二分查找算法
    【技术宅9】遍历一个文件夹下的所有文件和子文件夹
    【技术宅7】一个或多个虚拟主机配置方法
    【技术宅6】把一个无限级分类循环成tree结构
    【技术宅5】抓去网页数据的3种方法
    【技术宅4】如何把M个苹果平均分给N个小朋友
    【技术宅3】截取文件和url扩展名的N种方法
  • 原文地址:https://www.cnblogs.com/yl0604/p/10111771.html
Copyright © 2011-2022 走看看