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();
    
    // 通过一个工厂,把一个族中的相关产品全都输出来了
     
  • 相关阅读:
    Linux_LEMP
    Linux_LEMP
    Linux_指令杂烩
    Linux_指令杂烩
    Linux_SELinux使用
    AWS S3存储基于Hadoop之上的一致性保证
    Ozone数据写入过程分析
    Ozone Datanode的分布式元数据管理
    聊聊Ozone的Topology Awareness
    Ozone数据探查服务Recon的启用
  • 原文地址:https://www.cnblogs.com/yl0604/p/10111771.html
Copyright © 2011-2022 走看看