静态工厂
用一个工厂类去封装具有相同属性的其他类的new的工厂。这个方法是静态的,称之为静态工厂。
简单例子:AnimalFactory 工厂,里面生产孵化各种动物,都在这一个大工厂里
public interface Animal {
void getAnimal();
}
class Cat implements Animal {
@Override
public void getAnimal() {
System.out.println("喵喵我是一只猫");
}
}
class Dog implements Animal {
@Override
public void getAnimal() {
System.out.println("汪汪我是一只狗");
}
}
class AnimalFactory {
public static Animal getCat() {
return new Cat();
}
public static Animal getDog() {
return new Dog();
}
}
class TestClass {
public static void main(String[] agrs) {
Animal animal =AnimalFactory.getCat();
animal.getAnimal();
animal =AnimalFactory.getDog();
animal.getAnimal();
}
}
优势:
1: 和构造器不同的第一优势在于,它们有名字,更容易知道想要表达的是啥,比如代理模式中生成代理类就是用的静态工厂方法Proxy.newProxyInstance
构造器必须是类名 :比如 Cat cat =new Cat("小猫"),而静态工厂则不用,一般都后缀instance,比如 MyFactory.newOldCatInstance(),MyFactory.newYoungCatInstance()
2:不用每次被调用时都创建新对象,减少内存开销,单例的写法也大都是用静态工厂方法来实现的
3:可以返回原返回类型的子类
4:可以有多个参数相同但名称不同的工厂方法
5:可以减少对外暴露的属性,比如上面的狗的年龄必须是1-3岁。
如果是传统的new的方法,很有可能传入一个不符合规则的年龄,无法控制调用方
public interface Animal {
void getAnimal();
}
class Cat implements Animal {
@Override
public void getAnimal() {
System.out.println("喵喵我是一只猫");
}
}
class Dog implements Animal {
String dogType;
int dogAge;
public Dog(int dogAge, String dogType) {
this.dogAge = dogAge;
this.dogType = dogType;
}
@Override
public void getAnimal() {
System.out.println("汪汪我是一只狗" + dogType);
}
}
class AnimalFactory {
private static final int ONE_YEARS_OLD = 1;
private static final int TWO_YEARS_OLD = 2;
private static final int THREE_YEARS_OLD = 3;
public static Animal getCat() {
return new Cat();
}
//#########对应上面的优点1、3、4 但无法保证调用方对age输入的限制 START###########
public static Animal getDogHsq(int age) {
return new Dog(age, "我是哈士奇");
}
public static Animal getDogHsq(String dogType) {
return new Dog(ONE_YEARS_OLD, dogType);
}
//#########对应上面的优点1、3、4 END###########
//#########对应上面的优点5 START###########
public static Animal getDogYearsOld(String dogType) {
return new Dog(ONE_YEARS_OLD, dogType);
}
public static Animal getDogYearsOld2(String dogType) {
return new Dog(TWO_YEARS_OLD, dogType);
}
//#########对应上面的优点5 END###########
}
想要啥动物,就继承一下Animal,直接工厂获取就行
缺点:
类的创建依赖工厂类,想要拓展业务需要修改工厂类,比如你想在搞一个小鸟出来,得修改AnimalFactory.java
工厂方法模式:
设计一个工厂的接口,你想要什么东西,就写个类继承于这个工厂,就好比上面的动物工厂,此时这个工厂规范化了,生产狗的新建一个车间小工厂,生产猫的新建一个车间小工厂....................
//省略上面的相关代码
//省略上面的相关代码
interface AnimalFactory{
Animal getAnimalByFactory();
}
class DogFactory implements AnimalFactory{
@Override
public Animal getAnimalByFactory() {
return new Dog();
}
}
class CatFactory implements AnimalFactory{
@Override
public Animal getAnimalByFactory() {
return new Cat();
}
}
class TestClass {
public static void main(String[] agrs) {
Animal animal =new CatFactory().getAnimalByFactory();
animal.getAnimal();
animal =new DogFactory().getAnimalByFactory();
animal.getAnimal();
}
}
如果再想生产鸟,只需要开启一个生产鸟的车间小工厂继承大工厂即可,这个大工厂是不需要动的。
缺点:
如果此时我不仅想生产动物,我想生产口罩了咋办?那么就得在AnimalFactory接口里增加 Mask getMaskByFactory,那么这样每个车间小工厂都会多出一个屋来生产口罩(因为都是同一个接口),但是其他车间小工厂是无法生产口罩的,无法在生产狗的车间小工厂生产其他物品,因为大工厂是AnimalFactory。也就是说工厂方法模式只适合来生产同一类产品。
interface AnimalFactory{
Animal getAnimalByFactory();
Mask getMaskByFactory();
}
抽象工厂模式
把大工厂分成2类子工厂,一个是Linda的工厂,有2个车间,负责生产狗和白口罩,一个是crry的工厂,有2个车间,负责生产猫和黑口罩。
如果想在生产汽车,那么就新建一个join工厂。
此时有3个子工厂:Linda的工厂,3个车间,负责生产狗和白口罩和汽车。carry的工厂,3个车间,负责生产猫和黑口罩和汽车。join工厂,3个车间,一个生产汽车,其他2个随意。
因为他们都在大工厂Factory里的,所以再开辟其他工厂很简单。工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
动物接口及实现类
public interface Animal {
void getAnimal();
}
class Cat implements Animal {
@Override
public void getAnimal() {
System.out.println("喵喵我是一只猫");
}
}
class Dog implements Animal {
@Override
public void getAnimal() {
System.out.println("汪汪我是一只狗");
}
}
口罩接口及实现类
interface Mask {
void getMask();
}
class BlackMask implements Mask {
@Override
public void getMask() {
System.out.println("我是一个黑口罩");
}
}
class WhiteMask implements Mask {
@Override
public void getMask() {
System.out.println("我是一个白口罩");
}
}
生产动物和口罩的接口
interface Factory {
Animal getAnimalByFactory();
Mask getMaskByFactory();
}
生产动物和口罩的实现类
class FactoryOfLinda implements Factory {
@Override
public Animal getAnimalByFactory() {
return new Dog();
}
@Override
public Mask getMaskByFactory() {
return new BlackMask();
}
}
class FactoryOfCarry implements Factory {
@Override
public Animal getAnimalByFactory() {
return new Cat();
}
@Override
public Mask getMaskByFactory() {
return new WhiteMask();
}
}
调用
class TestClass {
public static void main(String[] agrs) {
// linda 想生产一只狗
Factory factory = new FactoryOfLinda();
Animal animal = factory.getAnimalByFactory();
animal.getAnimal();
// carry想生产一只猫 只需要改动把FactoryOfLinda 换成FactoryOfCarry即可
factory = new FactoryOfCarry();
animal = factory.getAnimalByFactory();
animal.getAnimal();
// linda 想生产一个口罩
factory = new FactoryOfLinda();
Mask mask = factory.getMaskByFactory();
mask.getMask();
}
}
总结:
简单工厂:所有的东西都是一个大工厂生产,压力比较大,想扩展必须修改大工厂。
工厂方法:大工厂里面细分了车间小工厂,解决了简单工厂的缺点,但是只能生产一类东西。
抽象工厂:对工厂方法进行了更高的抽象,大工厂分为不同类型的子工厂,子工厂进行车间的划分。
===========================分割线============================================
抽象工厂常用场景是一个项目工程里使用了不同的数据库比如mysql、oracle等,需要动态切换不同的库,每个库的sql也不一定一样。
对于抽象工厂虽然解决了不少问题,但是如果大工厂接口进行了改变,那么下面的子工厂必须实现大工厂的方法,比如上面的生产汽车,下面的子工厂必须都生产汽车。
但是jdk1.8解决了上面的问题,jdk1.8新特性默认方法,允许接口里定义默认方法,如果子类的操作都一样,那么就不用实现此方法,由接口来统一处理