工厂模式

#1.设计模式原则

#单一职责原则:

生工作:

  1. 辅导员:生活辅导
  2. 学业导师:学业辅导 单一职责原则 :一个类只负责一项职责 不能存在多于一个导致类变更的原因 单一职责原则符合"高内聚,低耦合"的思想 单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则

#开闭原则(Open Close Principle)

  • 开闭原则 :对扩展开放,对修改关闭
  • 程序进行扩展的时候,不能修改原有的代码, 实现一个热插拔的效果
  • 为了使程序扩展性好,易于维护和升级:需要使用接口和抽象类

#里氏代换原则(Liskov Substitution Principle)

  • 里氏代换原则 :任何基类可以出现的地方,子类一定可以出现
  • LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受影响时, 基类才能真正被复用,衍生类也能够在基类的基础上增加新的行为
  • 里氏代换原则是对实现抽象化的具体步骤的规范:
    • 里氏代换原则是对开闭原则的补充
    • 实现开闭原则的关键步骤就是抽象化
    • 基类与子类的继承关系就是抽象化的具体实现

#依赖倒转原则(Dependence Inversion Principle)

  • 依赖倒转原则 :针对接口编程,依赖于抽象而不依赖于具体
  • 依赖倒转原则是开闭原则的基础

#接口隔离原则(Interface Segregation Principle)

  • 接口隔离原则 :使用多个隔离的接口,比使用单个接口要好,降低类之间的耦合度
  • 从接口隔离原则可以看出:设计模式就是一个软件的设计思想
  • 从大型软件架构出发,为了升级和维护方便 :降低依赖,降低耦合

#迪米特法则(最少知道原则)(Demeter Principle)

  • 迪米特法则:最少知道原则 ,一个实体应当尽量少的与其它实体发生相互作用,使得功能模块相互独立

#合成复用原则(Composite Reuse Principle)

  • 合成复用原则 :尽量使用合成或者聚合的方式,而不是使用继承
  • 避免类之间的紧耦合关系
  • 可以动态地替换组件

#2. 简单工厂模式

工厂模式主要是用于对实现逻辑的封装,并且通过对公共的接口提供对象的实列化的服务,在我添加新的类时不需大动干戈,只要修改一点点就好。

简单工厂的实例: img 简单工厂几种实现方式:

#2.1 静态工厂模式

手机类的接口,定义手机的规范:

public interface Phone {  
     void display();  
}

两种手机:Iphone和Huawei

public class IPhone implements Phone {  
    IPhone(){  
        this.display();  
    }  
    @Override  
    public void display() {  
        System.out.println("60hz+ios>120hz");  
    }  
}
public class Huawei implements Phone{  
    Huawei(){  
        this.display();  
    }  
    @Override  
    public void display() {  
        System.out.println("4g+harmony>5g");  
    }  
}

生产手机的工厂类:

public class PhoneFactory {  
    public Phone makePhone(String phoneType){  
        if(phoneType.equals("Iphone")){  
            return new IPhone();  
        } else if (phoneType.equals("Huawei")) {  
            return new Huawei();  
        }  
        return null;  
    }  
}

示例:

public class demo {  
    public static void main(String[] args) {  
        PhoneFactory phoneFactory = new PhoneFactory();  
        Phone iphone = phoneFactory.makePhone("Iphone");  
    }  
}
//输出;60hz+ios>120hz
  1. 将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。

  2. 要点:当你需要什么,只需要传入一个==正确的参数==,就可以获取你所需要的对象,而无须知道其创建细节。

  3. 问题:工厂指责过重,增加新的产品需要修改工厂类的判断逻辑,需要修改代码,这一点与开闭原则是相违背的。

由此问题,想到应该去改进。 一种思路:利用反射

#2.2 利用反射来实现简单工厂模式

产品类的代码不变

public class PhoneFactory {  //反射工厂
    private static final Map<String,Class> phoneMap = new HashMap<>();  
    public static void addPhoneMap(String phoneType,Class newPhone){  
        phoneMap.put(phoneType,newPhone);  
    }  
  
    public Phone makePhone(String phoneType) throws Exception {  
        Class phoneClass = phoneMap.get(phoneType);  
        return (Phone) phoneClass.newInstance();  
    }  
}

示例:

public class demo {  
    public static void main(String[] args) throws Exception {  
        addPhoneMap("IPhone", IPhone.class);  
        PhoneFactory phoneFactory = new PhoneFactory();  
        Phone iphone = phoneFactory.makePhone("IPhone");  
    }  
}

但这种方式也有缺点:反射会降低程序的运行效率,对性能要求较高的场景应该避免这种写法。

所以就有了下面的设计模式:工厂模式。

#3. 工厂模式

和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,我们的工厂类直接被抽象化,需要具体特定化的逻辑代码转移到实现抽象方法的子类中,这样我们就不要再去修改工厂类(即:不用再去做什么if else 修改)这也是我们当前比较常用的一种方式。(即再创造一个工厂用于创造工厂类对象)如图所示: img

以图片加载器为例: Product:

public interface Reader {  
    void read();  
}

public class PngReader implements Reader {  //加载jpg
    @Override  
    public void read() {  
        System.out.print("read png");  
    }  
}

public class JpgReader implements Reader {  //加载png
    @Override  
    public void read() {  
        System.out.print("read jpg");  
    }  
}

Factory:

public interface ReaderFactory {  
    Reader getReader();  
}

public class JpgReaderFactory implements ReaderFactory{  //生产jpgreader的工厂
    @Override  
    public Reader getReader() {  
        return new JpgReader();  
    }  
}

public class PngReaderFactory implements ReaderFactory{  //生产pngreader的工厂
    @Override  
    public Reader getReader() {  
        return new PngReader();  
    }  
}

Demo:

public class demo {  
    public static void main(String[] args) {  
        ReaderFactory readerFactory = new JpgReaderFactory();  
        Reader reader = readerFactory.getReader();  
        reader.read();  
    }  
}
//output:read jpg

和简单工厂对比一下,最根本的区别在于,简单工厂只有一个统一的工厂类,而工厂方法是针对每个要创建的对象都会提供一个工厂类,这些工厂类都实现了一个工厂基类(本例中的ReaderFactory )。 使用场景: (1)客户端不需要知道它所创建的对象的类。例子中我们不知道每个图片加载器具体叫什么名,只知道创建它的工厂名就完成了床架过程。
(2)客户端可以通过子类来指定创建对应的对象。

问题:什么时候用简单工厂模式,什么时候用工厂模式呢?

引用设计模式之美里面的一句话:当对象的创建逻辑比较复杂,不只是简单的 new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,我们推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂。 而使用简单工厂模式,将所有的创建逻辑都放到一个工厂类中,会导致这个工厂类变得很复杂。

工厂模式下还可以进一步延伸为抽象工厂模式:

#4. 抽象工厂模式

问题:假设你正在开发一款家具商店模拟器。 你的代码中包括一些类, 用于表示:

  1. 一系列相关产品, 例如 椅子Chair 、 ​ 沙发Sofa和 咖啡桌Coffee­Table 。
  2. 系列产品的不同变体。 例如, 你可以使用 现代Modern 、  维多利亚Victorian 、  装饰风艺术Art­Deco等风格生成 椅子 、  沙发和 咖啡桌 。 如图: img 用上面的工厂模式去实现的话,就需要一个椅子抽象工厂,沙发抽象工厂和咖啡桌抽象工厂,显然不够优雅,我们的目的是利用一个抽象工厂就可以生产所有类型的家具。

工厂方法类中只有一个抽象方法,要想实现多种不同的类对象,只能去创建不同的具体工厂方法的子类来实列化,而抽象工厂 则是让一个工厂负责创建多个不同类型的对象

该例应用抽象工厂模式的示意图:img 项目组织: img

代码示例的话太长了,这里先不放了。

抽象工厂模式的结构 img

应用场景:

  1. 如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。
  2. 如果你有一个基于一组抽象方法的类, 且其主要功能因此变得不明确, 那么在这种情况下可以考虑使用抽象工厂模式。