Spring的笔记写了一半,突然想复习一下工厂模式,所以写一篇。
前言
面向对象设计的基本原则
谈到工厂模式我要先提一下,面向对象设计的基本原则:
单一职责原则(Single Responsibility Principle)
每一个类应该专注于做一件事情。
里氏替换原则(Liskov Substitution Principle)
超类存在的地方,子类是可以替换的。
依赖倒置原则(Dependence Inversion Principle)
实现尽量依赖抽象,不依赖具体实现。
接口隔离原则(Interface Segregation Principle)
应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。
迪米特法则(Law Of Demeter)
又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。
开闭原则(Open Close Principle)
面向扩展开放,面向修改关闭。
组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
尽量使用组合/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。
工厂模式的核心本质
- 通过用工厂的方法来new对象,来实现对象的实例化。
- 调用者和实现者 相互解藕
简单工厂模式
简单工厂模式,虽然简单,但是它也是最常用的工厂模式。
什么都不说,这章,我们直接撸代码。
先来个狗的抽象类。
public interface Dog{void bark();}
再来个旺财的实现类。
public class Money implements Dog{@Overridepublic void bark(){system.out.println("旺财叫!");}}
然后来个来福的实现类。
public class Lucky implements Dog{@Overridepublic void bark(){system.out.println("来福叫!");}}
现在我们的依赖关系为:
Dog <——- Money^|—<——-Lucky
如果我们平时想要调用这两个实现类,我们通常会这样:
public class client{public static void main(String\[\] args){Dog money = new Money();Dog Lucky = new Lucky();money.bark();Lucky.barck();}}
输出应该是:
旺财叫!
来福叫!
这样造成的问题是:
client既要知道Dog,还要知道Dog的分类才能调用成功。
然后我们来一个Dog的工厂类
public class DogFactory{public static Dog getDog(String type){switch(type){case "Money":return new Money();break;case "Lucky":return new Lucky();break;default:throw new DogNotFoundException(DOG_NOT_FOUND);}}}
然后我们就可以这样那拿到我们想要的狗了:
public class Client{public static void main(String\[\] args){Dog money = DogFactory.getDog("Money");Dog Lucky = DogFactory.getDog("Lucky");money.bark();Lucky.barck();}}
输出应该还是:
旺财叫!
来福叫!
现在的依赖关系虽然较复杂,但是已经很解藕了。
现在客户端,只需要知道,我要Dog,我要什么狗。然后就不亲自去造狗,而是直接去找工厂要。工厂知道后,就开始找有没有这个狗,有就返回给客户端,没有嘛,就报一个简单的异常。
然后,你不止可以选择switch的方式来创建工厂类还可以用if else和静态方法调用。
if else
public class DogFactory{public static Dog getDog(String type){if("Money".equals(type)){return new Money();}else("Lucky".equals(type)){return new Lucky();}// 异常省略了。}}
静态方法
public class DogFactory{public static Dog getMoney(){return new Money();}public static Dog getLucky(){return new Lucky();}}
当然工厂模式的命名以 createXX 更好,但是我总觉得创造一个 旺财怪怪的,所以改成了get。
工厂方法模式
我们还是先搞三个类
public interface Dog{void bark();}
public class Money implements Dog{@Overridepublic void bark(){system.out.println("旺财叫!");}}
public class Lucky implements Dog{@Overridepublic void bark(){system.out.println("来福叫!");}}
这个模式,每个实现类都需要自己的工厂类
所以我们创建 旺财 和 来福 各自的工厂类 还有 Dog工厂的抽象类
public interface DogFactory{Dog getDog();}
public class MoneyFactory implements DogFactory{@Overridepublic Dog getDog(){return new Money();}}
public class LuckyFactory implements DogFactory{@Overridepublic Dog getDog(){return new Lucky();}}
然后写客户端
public class Client{public static void main(String [] args){Money money = MoneyFactory.getDog();Lucky lucky = LuckyFactory.getDog();money.bark();Lucky.bark();}}
这样就保证了开闭原则,扩展时不修改原有代码,但是类太XX多了。
我也认为这样设计很蠢,贼蠢。
抽象工厂模式
抽象工厂模式,是为了解决多层次情况。比如:我们现在把来福和旺财看成两类狗,然后再加入狗的颜色属性
然后我们需要输出也就是得到:
例如:
黑色旺财叫!
白色旺财叫!
黑色来福叫!
白色来福叫!
核心思想就是,我们通过工厂类来指定一个来福工厂类还是旺财工厂类,
然后用它们各自工厂类的创建狗方法来生成上面的结果。
然后我们再让整体结构复杂一点,添加点属性。
所以我们的整体结构现在变成了现在这个样子:
白色狗抽象类和具体实现类
public interface WhiteDog{void bark();}public class MoneyWhiteDog implements WhiteDog{public void bark(){sout("白色旺财叫!")};}public class LuckyWhiteDog implements WhiteDog{public void bark(){sout("白色来福叫!")};}
黑色狗抽象类和具体实现类
public interface BlackDog{void bark();}
public class MoneyBlackDog implements BlackDog{public void bark(){sout("黑色旺财叫!")};}
public class LuckyBlackDog implements BlackDog{public void bark(){sout("黑色来福叫!")};}
狗的工厂抽象类
public interface DogFactory{WhiteDog createWhiteDog();BlackDog createBlackDog();}
旺财工厂类
public class MoneyFactory implements DogFactory{@OverrideWhiteDog createWhiteDog(){return new MoneyWhiteDog;};BlackDog createBlackDog(){return new MoneyBlackDog};}
来福工厂类
public class LuckyFactory implements DogFactory{@OverrideWhiteDog createWhiteDog(){return new LuckyWhiteDog;};BlackDog createBlackDog(){return new LuckyBlackDog};}
public static void main(String [] args){DogFactory dogFactory = new MoneyFactory();MoneyWhiteDog moneyWhiteDog = dogFactory.createWhiteDog();moneyWhiteDog.bark();}
如果不出意外的话,输出是:“白色旺财叫!”