Java设计模式(4):工厂模式
工厂模式种类
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
一.简单工厂模式
又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例。
定义一个用于创建对象的接口,让子类决定实例化哪个类。
工厂方法模式属于创建型模式。
UML类图
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来创建的要慢。
二.工厂方法模式
工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
工厂方法模式属于创建型模式。
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等生产出电脑来。
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();
//还可以有很多其他的创建不同对象的工厂类
}
}
应用场景
生产多个产品组合的对象时。
优点
代码解耦,创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建。
缺点
如果增加新的产品,则修改抽象工厂和所有的具体工厂,违反了开放封闭原则。
工厂方法模式与抽象工厂模式比较
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性。
抽象工厂模式则可以提供多个产品对象,而不是单一的产品对象。