前言
- 工厂模式
– 我们通常是通过 new 来进行创建对象,这样导致程序的耦合性很高,而工厂模式就是用于代替直接 new 的一种模式。 - 三种工厂模式
– 简单工厂模式:用工厂类代替 new ,降低类之间的耦合度;
– 工厂方法模式:将具体的处理交给子类;用于生产某一类产品;
– 抽象工厂模式:用于生产一系列产品;
简单工厂(静态工厂)
- 现在有一需求(举例),需要生产一些java开发工具,如Idea,Eclipse等。
- UML设计图如下
- 代码实现
//简单工厂
public class SimpleFactory {
/**
* 使用的是简单的静态工厂模式
* @param type
* @return
*/
public static Product createProduct(String type){
Product product = null;
if(type.equals("idea")){
product = new IdeaProduct();
}else if(type.equals("eclipse")){
product = new EclipseProduct();
}
return product;
}
}
//产品父类
public abstract class Product {
private String name;
public abstract void user();
}
//产品子类
public class IdeaProduct extends Product{
@Override
public void user() {
System.out.println("使用IDEA产品");
}
}
//产品子类
public class EclipseProduct extends Product {
@Override
public void user() {
System.out.println("使用eclipse产品");
}
}
- 使用
public class Test {
public static void main(String[] args) {
Product idea = SimpleFactory.createProduct("idea");
idea.user();
Product eclipse = SimpleFactory.createProduct("eclipse");
eclipse.user();
}
}
- 总结
特点:用于生产单个产品,将生产产品的逻辑封装在工厂类中;
优点:去除客户端(上面的Test类)与具体产品的依赖,客户端无需关系产品生产细节;
缺点:添加新产品需要修改工厂类,违背开闭原则;比如添加一个STS开发工具,需要在工厂类中添加新的判断;
工厂方法模式
- 分析:==抽象的本质是不考虑具体怎么实现,而是仅关注接口。==所以我们可以对简单工厂进一步抽象,简单工厂是违背了开闭原则,开闭原则的一种体现就是把打破开闭原则的地方进行抽象(利用接口或者抽象类),在上面例子中根据不同的条件创建不同的对象,我们可以将具体创建对象的工作交给子类来完成。
- UML设计图如下
- 代码实现
//抽象工厂
public abstract class Factory {
public abstract Product createProduct();
}
//工厂子类
public class IdeaFactory extends Factory {
@Override
public Product createProduct() {
return new IdeaProduct();
}
}
//工厂子类
public class EclipseFactory extends Factory {
@Override
public Product createProduct() {
return new EclipseProduct();
}
}
//产品抽象类
public abstract class Product {
public abstract void user();
}
//产品子类
public class IdeaProduct extends Product {
@Override
public void user() {
System.out.println("使用IDEA开发");
}
}
//产品子类
public class EclipseProduct extends Product {
@Override
public void user() {
System.out.println("使用Eclipse开发");
}
}
- 使用
public class Test {
public static void main(String[] args) {
Factory ideafactory = new IdeaFactory();
Product idea = ideafactory.createProduct();
idea.user();
Factory eclipseFactory = new EclipseFactory();
Product eclipse = eclipseFactory.createProduct();
eclipse.user();
}
}
- 第二种优化方式(其实也是对抽象工厂模式的优化)
//抽象工厂:使用泛型(其实也是一种抽象);使用反射
public abstract class AbstractFactory {
//使用 extends :给泛型类型一个约束,从而限定只能返回 Product 类型对象
public abstract <T extends Product> T createProduct(Class<T> clzz) throws Exception;
}
//具体工厂实现
public class ConcreteFactory extends AbstractFactory {
@Override
public <T extends Product> T createProduct(Class<T> clzz) throws Exception {
T instance = (T) Class.forName(clzz.getName()).newInstance();
return instance;
}
}
//调用
public class Test {
public static void main(String[] args) {
AbstractFactory factory = new ConcreteFactory();
try {
Product product = factory.createProduct(EclipseProduct.class);
product.user();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 总结
特点:生产某一类类型产品;一种产品对应一个工厂类;具体实现交给子类;其实工厂方法模式的定义更偏向于在父类中定义产品生产的流程(算法),而具体的实现交给子类实现。
//示例代码
public abstract class Factory {
public abstract Product createProduct();
public abstract void register(Product product);
//final 定义方法无法被重载,子类只需提供抽象方法的实现
public final Product create(){
Product product = createProduct();
register(product);
return product;
}
}
优点:添加新产品只需添加相应工厂类,符合开闭原则、里氏替换原则;
缺点:产品多时,工厂泛滥;
抽象工厂模式
- 个人理解,抽象工厂模式与工厂方法模式在形式上没有什么区别,但在侧重点上有一些区别,工厂方法侧重于:更偏向于在父类中定义产品生产的流程(算法),而具体的实现交给子类实现。而抽象工厂侧重于生产零件并将零件组装成产品,其实也可把零件当成一种产品;
- 代码实现
代码出处: https://blog.youkuaiyun.com/michael_yt/article/details/82112443
//1.抽象工厂
public abstract class CarFactory {
/**
* 生产轮胎
*
* @return 轮胎
* */
public abstract ITire createTire();
/**
* 生产发动机
*
* @return 发动机
* */
public abstract IEngine createEngine();
/**
* 生产制动系统
*
* @return 制动系统
* */
public abstract IBrake createBrake();
}
//2.三个产品抽象接口
public interface ITire {
/**
* 轮胎
*/
void tire();
}
public interface IEngine {
/**
*发动机
*/
void engine();
}
public interface IBrake {
/**
*制动系统
*/
void brake();
}
//3.根据抽象接口定义不同的对象
public class NormalBrake implements IBrake{
@Override
public void brake() {
System.out.println("普通制动");
}
}
public class SeniorBrake implements IBrake{
@Override
public void brake() {
System.out.println("高级制动");
}
} //后面的定义省略。。。。。。。。。。。。。
//4.实现具体的工厂类
public class Q3Factory extends CarFactory{
@Override
public ITire createTire() {
return new NormalTire();
}
@Override
public IEngine createEngine() {
return new DomesticEngine();
}
@Override
public IBrake createBrake() {
return new NormalBrake();
}
}
//5.客户端使用
public class Client {
public static void main(String[] args) {
CarFactory factoryQ3 = new Q3Factory();
factoryQ3.createTire().tire();
factoryQ3.createEngine().engine();
factoryQ3.createBrake().brake();
System.out.println("---------------");
}
}
比如各种数据库的SqlSessionFactory,其实都使用了抽象工厂模式;
- 总结:
特点:用于生产多种零件(产品);
优点:添加新产品只需添加相应工厂类,符合开闭原则、里氏替换原则;
缺点:新增零件时,所有工厂类都需要修改(不知是我理解不够还是本质就是这样,我觉得抽象工厂模式不是很优雅)
多说一点
- 上面代码中,工厂父类(除简单工厂)也都可以定义为接口;
- 下面这种优化模式很值得去回味(代码再写一遍),上面说这也是抽象工厂的一种优化:我们可以把所有零件都定义为’Product’ 类类型或者空接口(更倾向于接口,扩展性更高)或者简单直接使用泛型 T,然后利用反射创建对象,你会发现这个方法就可以为你创建所有的零件(产品),这看起来很优雅。
//抽象工厂:使用泛型(其实也是一种抽象);使用反射创建对象
public abstract class AbstractFactory {
//使用 extends :给泛型类型一个约束,从而限定只能返回 Product 类型对象
public abstract <T extends Product> T createProduct(Class<T> clzz) throws Exception;
}
//具体工厂实现
public class ConcreteFactory extends AbstractFactory {
@Override
public <T extends Product> T createProduct(Class<T> clzz) throws Exception {
T instance = (T) Class.forName(clzz.getName()).newInstance();
return instance;
}
}