Java设计模式(4):工厂模式

工厂模式种类

  1. 简单工厂模式
  2. 工厂方法模式
  3. 抽象工厂模式

一.简单工厂模式

又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例。

定义一个用于创建对象的接口,让子类决定实例化哪个类。

工厂方法模式属于创建型模式。

UML类图

Java设计模式(4):工厂模式

Product(抽象产品类):要创建的复杂对象,定义对象的公共接口。
ConcreteProduct(具体产品类):实现Product接口。
Factory(工厂类):返回ConcreteProduct实例。

案例

创建抽象产品类,定义公共接口

public abstract class Animal {
	public abstract void eat();
}

创建具体产品类,继承抽象产品类

public class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("猫吃饭");
	}
}

public class Dog extends Animal {

	@Override
	public void eat() {
		System.out.println("狗吃饭");
	}
}

创建工厂类,创建具体的产品

public class AnimalFactory {

	private AnimalFactory() {
	}

	// public static Dog createDog() {
	// return new Dog();
	// }
	//
	// public static Cat createCat() {
	// return new Cat();
	// }

	public static Animal createAnimal(String type) {
		if ("dog".equals(type)) {
			return new Dog();
		} else if ("cat".equals(type)) {
			return new Cat();
		} else {
			return null;
		}
	}
}

测试

public class AnimalDemo {
	public static void main(String[] args) {
		// 具体类调用
		Dog d = new Dog();
		d.eat();
		Cat c = new Cat();
		c.eat();
		System.out.println("------------");

		// 工厂有了后,通过工厂给造
		// Dog dd = AnimalFactory.createDog();
		// Cat cc = AnimalFactory.createCat();
		// dd.eat();
		// cc.eat();
		// System.out.println("------------");

		// 工厂改进后
		Animal a = AnimalFactory.createAnimal("dog");
		a.eat();
		a = AnimalFactory.createAnimal("cat");
		a.eat();

		// NullPointerException
		a = AnimalFactory.createAnimal("pig");
		if (a != null) {
			a.eat();
		} else {
			System.out.println("对不起,暂时不提供这种动物");
		}
	}
}

应用场景

生成复杂对象时,确定只有一个工厂类,可以使用简单工厂模式。否则有多个工厂类的话,使用工厂方法模式。

优点

代码解耦,创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,从而明确了各个类的职责

缺点

违背开放封闭原则,这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护。

简单工厂模式使用了静态工厂方法,因此静态方法不能被继承和重写。

简单工厂模式的优化:反射实现工厂类

由于简单工厂模式新增产品时需要直接修改工厂类,违反了开放封闭原则(一个对象对扩展开放,对修改关闭)。因此可以使用反射来创建实例对象,确保能够遵循开放封闭原则。

public class Factory {

    public static <T extends Product> T create(Class<T> clz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clz.getName()).newInstance();//反射出实例
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}

使用反射来实现工厂类,新增产品时无需修改工厂类,但是使用反射来创建实例对象的话会比正常使用new来创建的要慢。

二.工厂方法模式

工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。

工厂方法模式属于创建型模式。

Java设计模式(4):工厂模式

Product(抽象产品类):要创建的复杂对象,定义对象的公共接口。
ConcreteProduct(具体产品类):实现Product接口。
Factory(抽象工厂类):该方法返回一个Product类型的对象。
ConcreteFactory(具体工厂类):返回ConcreteProduct实例。

案例

创建抽象产品类,定义公共接口

public abstract class Animal {
	public abstract void eat();
}

创建具体产品类,继承抽象产品类

public class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("猫吃饭");
	}
}

public class Dog extends Animal {

	@Override
	public void eat() {
		System.out.println("狗吃饭");
	}
}

创建抽象工厂类,定义公共接口

public interface Factory {
	public abstract Animal createAnimal();
}

创建具体工厂类,继承抽象工厂类,实现创建具体的产品

public class CatFactory implements Factory {

	@Override
	public Animal createAnimal() {
		return new Cat();
	}
}

public class DogFactory implements Factory {

	@Override
	public Animal createAnimal() {
		return new Dog();
	}
}

测试

public class AnimalDemo {
	public static void main(String[] args) {
		// 需求:我要买只狗
		Factory f = new DogFactory();
		Animal a = f.createAnimal();
		a.eat();
		System.out.println("-------");
		
		//需求:我要买只猫
		f = new CatFactory();
		a = f.createAnimal();
		a.eat();
	}
}

应用场景

生成复杂对象时,无需知道具体类名,只需知道相应的工厂方法即可。

优点

符合开放封闭原则。新增产品时,只需增加相应的具体产品类和相应的工厂子类即可。

符合单一职责原则。每个具体工厂类只负责创建对应的产品。

缺点

一个具体工厂只能创建一种具体产品。

增加新产品时,还需增加相应的工厂类,系统类的个数将成对增加,增加了系统的复杂度和性能开销。

引入的抽象类也会导致类结构的复杂化。

工厂方法模式与简单工厂模式比较

工厂方法模式有抽象工厂类,简单工厂模式没有抽象工厂类且其工厂类的工厂方法是静态的。

工厂方法模式新增产品时只需新建一个工厂类即可,符合开放封闭原则;而简单工厂模式需要直接修改工厂类,违反了开放封闭原则。

Android中工厂方法模式的应用

ThreadFactory就是使用了工厂方法模式来生成线程的,线程就是ThreadFactory的产品。

//抽象产品:Runnable
    public interface Runnable {
        public abstract void run();
    }
    
    //具体产品:Thread
    public class Thread implements Runnable {
        //构造方法
        public Thread(Runnable target, String name) {
            init(null, target, name, 0);
        }
        
        @Override
        //实现抽象产品的抽象方法
        public void run() {
            if (target != null) {
                target.run();
            }
        }
        
        //其他代码略
    }
    
    
    //抽象工厂:ThreadFactory
    public interface ThreadFactory {
        Thread newThread(Runnable r);
    }
    
    //具体工厂:AsyncTask中的实现
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        
        //实现抽象工厂的抽象方法
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//返回Thread这个产品
        }
    };

三.抽象工厂模式

为创建一组相关或者相互依赖的对象提供一个接口,而无需指定它们的具体类。

抽象工厂模式属于创建型模式。

工厂方法模式每个工厂只能创建一种类型的产品,而抽象工厂模式则能够创建多种类型的产品。

例如:硬盘工厂只生产硬盘这种产品,而电脑工厂则组合不同的硬盘、内存、CPU等生产出电脑来。

Java设计模式(4):工厂模式

AbstractProduct(抽象产品类):定义产品的公共接口。
ConcreteProduct(具体产品类):定义产品的具体对象,实现抽象产品类中的接口。
AbstractFactory(抽象工厂类):定义工厂中用来创建不同产品的方法。
ConcreteFactory(具体工厂类):实现抽象工厂中定义的创建产品的方法。

案例

创建2种抽象产品类

public abstract class Animal {
    public abstract void eat();
}

public abstract class Person {
    public abstract void sing();
}

创建2种抽象产品类具体产品类

继承Animal 的具体产品类:

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃饭");
    }
}

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃饭");
    }
}

继承Person的具体产品类:

public class Student extends Person {
    @Override
    public void sing() {
        System.out.println("学生唱歌");
    }
}

public class Teacher extends Person {
    @Override
    public void sing() {
        System.out.println("老师唱歌");
    }
}

创建抽象工厂类

定义工厂中用来创建不同产品的方法:

public abstract class AbstractFactory  {

    public abstract Animal createAnimal();

    public abstract Person createPerson();
}

创建具体工厂类

每创建不同的对象都定义一个工厂

public class FirstFactory extends AbstractFactory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }

    @Override
    public Person createPerson() {
        return new Student();
    }
}
public class SecondFactory extends AbstractFactory {

    @Override
    public Animal createAnimal() {
        return new Cat();
    }

    @Override
    public Person createPerson() {
        return new Teacher();
    }
}

测试

public class Test {
    public static void main(String[] args) {

        //负责创建狗和学生的工厂类
        FirstFactory firstFactory = new FirstFactory();
        firstFactory.createPerson().sing();
        firstFactory.createPerson().sing();

        //负责创建猫和老师的工厂类
        SecondFactory secondFactory = new SecondFactory();
        secondFactory.createPerson().sing();
        secondFactory.createAnimal().eat();

        //还可以有很多其他的创建不同对象的工厂类

    }
}

应用场景

生产多个产品组合的对象时。

优点

代码解耦,创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建。

缺点

如果增加新的产品,则修改抽象工厂和所有的具体工厂,违反了开放封闭原则。

工厂方法模式与抽象工厂模式比较

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性。

抽象工厂模式则可以提供多个产品对象,而不是单一的产品对象。