1、先说说面向对象的基本原则:(简单复习复习,以前学得都忘得七七八八)
- OCP(开闭原则,Open-Closed Principle): 一个软件的实体应当对扩展开放,对修改关闭。
- DIP(依赖倒转原则,Dependence Inversion Principle): 要针对接口编程,不要针对实现编程。
- LoD(迪米特法则,Law of Demeter):只与你直接的朋友通信,而避免与陌生人进行通信。(即类与类之间的关系尽量少)
2、工厂模式:
a、核心本质:
- 实例化对象,用工厂方法代替 new 操作。
- 将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
b、详细的分类:
- 简单工厂模式:用来生产统一等级结构中的任意产品。(对于增加新的产品,需要修改已有的代码)
- 工厂方法模式:用来生产统一等级结构中的固定产品。(支持增加任意产品)
- 抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力,支持增加产品族)
3、简单工厂模式:
- 简单工厂模式也叫做静态工厂模式,就是工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。
- 对于增加新产品,如果不能够修改代码,是无法扩展的。
- 简单的代码演示:
a、首先先创建一个接口和三个类,其中包含一个名为 Client01.java 的测试类,以及其类图的关系:
package com.geeklicreed.singlefactory; public interface Car { void run(); }
package com.geeklicreed.singlefactory; public class Byd implements Car{ @Override public void run() { System.out.println("比亚迪在跑!"); } }
package com.geeklicreed.singlefactory; public class Audi implements Car{ @Override public void run() { System.out.println("奥迪在跑"); } }
package com.geeklicreed.singlefactory; public class Client01 { public static void main(String[] args) { Audi audi = new Audi(); Byd byd = new Byd(); audi.run(); byd.run(); /* 输出结果为: 奥迪在跑 比亚迪在跑! */ } }
- 注:我们可以看到,调用者 client 与 实现者 Byd 和 Audi 紧密耦合,调用者不仅需要知道其 Car 接口,还要清楚其 Car 接口下实现的所有的实现类。(就像我们原始社会一样,什么样的事情都得自己做,啥事都得知道,会活活把人累死的。)
b、在所在包中创建一个简单的汽车生产工厂 SingleCarFactory,它代替我们生产汽车:
package com.geeklicreed.singlefactory; public class SingleCarFactory { public static Car createCar(String carType){ if(carType == "奥迪"){ return new Audi(); }else if(carType == "比亚迪"){ return new Byd(); }else { return null; } } }
package com.geeklicreed.singlefactory; public class Client { public static void main(String[] args) { Byd byd = (Byd) SingleCarFactory.createCar("比亚迪"); Audi audi = (Audi) SingleCarFactory.createCar("奥迪"); byd.run(); audi.run(); /*输出结果为: 比亚迪在跑! 奥迪在跑*/ } }
- 注:可以看到,调用者 Client02 只和 SingleCarFactory 与接口 Car 耦合,不与实际的实现类打交道。
4、工厂方法模式:
- 为了避免简单工厂模式的缺点,即不完全满足 OCP(开闭原则)
- 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
- 简单代码演示:
a、和简单工厂一样,一个 Car 接口和 Byd 和 Audi 的实现类,此外再加上一个 CarFactory 接口 和 BydFactory 实现类和 AudiFactory 实现类。
package com.geeklicreed.singlefactory; public interface Car { void run(); }
package com.geeklicreed.singlefactory; public class Audi implements Car{ @Override public void run() { System.out.println("奥迪在跑"); } }
package com.geeklicreed.singlefactory; public class Byd implements Car{ @Override public void run() { System.out.println("比亚迪在跑!"); } }
package com.geeklicreed.singlefactory; public interface CarFactory { Car createFactory(); }
package com.geeklicreed.singlefactory; public class AudiFactory implements CarFactory{ @Override public Car createFactory() { return new Audi(); } }
package com.geeklicreed.singlefactory; public class BydFactory implements CarFactory{ @Override public Car createFactory() { return new Byd(); } }
b、在 Client03 的这个测试类中填写代码,以及工厂方法模式的示例的类图
package com.geeklicreed.singlefactory; public class Client { public static void main(String[] args) { Car car1 = new AudiFactory().createFactory(); Car car2 = new BydFactory().createFactory(); car1.run(); car2.run(); /*输出结果为: 奥迪在跑 比亚迪在跑!*/ } }
- 注:我们可以看到,工厂方法模式中,调用者 Client03 只需要和 CarFactory 与 AudiFactory 以及 BydFactory 耦合,与其他类并没有关系。
5、抽象工厂模式:
- 用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
- 抽象工厂模式是工厂方法模式的升级版,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
- 简单的代码演示:
a、创建 Engine、Seat 和 Type 接口,以及其对应的实现类 LuxuryEngine 和 LowEngine,LuxurySeat 和 LowSeat,LuxuryType 和 LowType 。
package com.geeklicreed.abstractfactory; public interface Engine { void start(); void run(); } class LuxuryEngine implements Engine{ public void start(){ System.out.println("启动块!"); } public void run(){ System.out.println("耗油量少"); } } class LowEngine implements Engine{ public void start(){ System.out.println("启动慢!"); } public void run() { System.out.println("耗油量多"); } }
package com.geeklicreed.abstractfactory; public interface Type { void abrase(); } class LuxuryType implements Type{ public void abrase(){ System.out.println("行驶不磨损!"); } } class LowType implements Type{ public void abrase(){ System.out.println("行驶磨损,不耐用!"); } }
package com.geeklicreed.abstractfactory; public interface Seat { void comfort(); } class LuxurySeat implements Seat { @Override public void comfort() { System.out.println("坐得舒服"); } } class LowSeat implements Seat { @Override public void comfort() { System.out.println("坐得感觉还行吧"); } }
b、创建 CarFactory 接口,以及其对应的实现类 LowCarFactory 和 LuxuryCarFactory 。
package com.geeklicreed.abstractfactory; public interface CarFactory { Engine createEngine(); Seat createSeat(); Type createType(); }
package com.geeklicreed.abstractfactory; public class LowCarFactory implements CarFactory{ @Override public Engine createEngine() { return new LowEngine(); } @Override public Seat createSeat() { return new LowSeat(); } @Override public Type createType() { return new LowType(); } }
c、创建 Client04 测试类,这个抽象工厂的示例的类图如下所示。
package com.geeklicreed.abstractfactory; public class Client { public static void main(String[] args) { CarFactory carFactory = new LowCarFactory(); Engine engine = carFactory.createEngine(); Seat seat = carFactory.createSeat(); engine.start(); engine.run(); seat.comfort(); /*输出结果为: 启动慢! 耗油量多 坐得感觉还行吧*/ } }
- 注:可以看到,client04 调用者只与 CarFactory 接口和其实现类 LuxuryCarFactory 和 LowCarFactory 相耦合。
6、简单工厂模式和工厂方法模式PK:
- 结构复杂度:简单工厂模式占优。简单工厂模式只需要一个工厂类,而工厂方法模式的工厂类随着产品的增加而增加,增加了类结构的复杂度。
- 代码复杂度:代码复杂度和结构复杂度是一对矛盾。既然简单工厂模式在结构方面相对简洁,那么他在代码方面肯定比工厂方法模式复杂的多。
- 客户端编程难度:工厂方法模式虽然在工厂类结构中引入接口从而满足 OCP,但是在客户端编码中需要对类进行实例化,而简单工厂模式的工厂类是个静态类,在客户端无需实例化,这无疑是一个吸引人的优点。
- 扩展性:工厂方法模式完全满足 OCP 原则,具备很好的扩展性,而简单工厂模式扩展性不足。
- 所以,综合上面的情况,根据设计理论建议:工厂方法模式。但是我们在实际开发中,一般会选择使用简单工厂模式。
7、应用场景:
- JDK 中 Calenda 的 getInstance方法。
- JDBC 中 Connection 对象的获取。
- Hibernate 中 SessionFactory 创建 Session。
- spring 中 IOC 容器创建管理 bean 对象。