往常痛点

  • 下面这段代码,看着没什么问题,利用接口抽象方法规定了gradeName()这个方法,GradeA去实现它,并写自己的逻辑,但是不利于拓展,比如我想加一个GradeB,Application就不能够帮我new出来想要的对象了,所以我们要改造一下,让我们new出自己想要的对象。
  1. public class GradeA implements GradeNameProvider{
  2. @Override
  3. public void gradeName(){
  4. System.out.println("通信三班");
  5. }
  6. public static void main(String[] args) {
  7. Application application = new Application();
  8. GradeNameProvider obj = application.getGrade();
  9. obj.gradeName();
  10. }
  11. }
  12. interface GradeNameProvider {
  13. abstract void gradeName();
  14. }
  15. class Application{
  16. public GradeNameProvider createGradeA(){
  17. return new GradeA();
  18. }
  19. public GradeNameProvider getGrade(){
  20. return createGrade();
  21. }
  22. }


简单工厂模式

  • 这样修改过后,每次新增班级只需要关注工厂类(GradeFactory)就可以了,简化了new对象的流程
  • 利用java的多态来实现,降低代码的耦合性。在工厂里生产不同的对象。由此,工厂和产品挂上钩了,联系上了。createGrade生产出来的都是独特的产品。
  • 简单工厂模式应该不算是设计模式里的一种,只能说算是一共解决方案
  • 结论:最好慎用,违反了设计模式的开闭原则,如果后期增加班级类,需要修改工厂方法


  1. interface GradeNameProvider {
  2. abstract void gradeName();}
  3. public class GradeA implements GradeNameProvider{
  4. @Override
  5. public void gradeName(){
  6. System.out.println("通信三班");
  7. }
  8. }
  9. class GradeB implements GradeNameProvider{
  10. @Override
  11. public void gradeName() {
  12. System.out.println("通信四班");
  13. }
  14. }
  15. class GradeFactory{
  16. public static GradeNameProvider createGrade(String type){
  17. if (type.equals("GradeA")){
  18. return new GradeA();
  19. }else if (type.equals("GradeB")){
  20. return new GradeB();
  21. }else {
  22. throw new RuntimeException("简单工厂里面暂时没有此班级,目前可以new GradeA、GradeB"); }
  23. }
  24. }
  25. class Application{
  26. private GradeNameProvider createGrade(String type){
  27. return GradeFactory.createGrade(type);
  28. }
  29. public GradeNameProvider getGrade(String type){
  30. return createGrade(type);
  31. }
  32. }
  33. class Test{
  34. public static void main(String[] args) {
  35. Application application = new Application();
  36. GradeNameProvider gradeName = application.getGrade("GradeB");
  37. gradeName.gradeName();//通信四班
  38. }
  39. }

工厂模式

  • 工厂模式的话肯定是要解决开闭原则这个问题的,不然改动原本代码是大忌,不要从理论上来说不会出问题,实际工作中经常嘴上说着保证没问题,结果上线就出故障。。。
  • 工厂模式解决了开闭原则和单一原则,通信三班就做通信三班的事情,不被其他业务打扰,互不干扰。
  • 结论:工厂模式还是有缺点的,如果班级类过多,我们就要生成很多的工厂类。假如我们要实现的班级接口不止一个,也就是有多个班级接口,不同班级接口有对应的产品族。什么是产品族呢?简单的理解就是,不同牌子产的车里面会有跑车类型,家庭类型,商用类型等的车,不同牌子的车的跑车类型的车可以组成一个产品族。对于这种情况我们可以采用抽象工厂模式。
  1. 我们先改造一下Application这个方法,老代码如下。

    1. class Application{
    2. private GradeNameProvider createGrade(String type){
    3. return GradeFactory.createGrade(type);
    4. }
    5. public GradeNameProvider getGrade(String type){
    6. return createGrade(type); }
    7. }


  2. 想要完成开闭原则的改造,首先要拿Application这个方法开刀,把createGrade变为抽象方法,然后新建一个子工厂类实现createGrade,return要生产的对象,说干就干,改造完的方法如下

    1. abstract class Application{
    2. abstract GradeNameProvider createGrade();
    3. public GradeNameProvider getGrade(){
    4. return createGrade();
    5. }
    6. }


  3. 想要把createGrade变为抽象方法,先要把Application变为抽象类,我们来测试一下改造过后怎么样,测试代码如下

    1. class Test{
    2. public static void main(String[] args) {
    3. Application application = new Application() {
    4. @Override
    5. GradeNameProvider createGrade() {
    6. return new GradeA();
    7. }
    8. };
    9. GradeNameProvider grade = application.getGrade();
    10. grade.gradeName();//通信三班
    11. }
    12. }


  4. 经过上面的测试之后,我们发现没有问题,现在就把GradeA和GradeB改造成工程模式吧!改造完的代码如下

    1. interface GradeNameProvider {
    2. abstract void gradeName();
    3. }
    4. public class GradeA implements GradeNameProvider{
    5. @Override
    6. public void gradeName(){
    7. System.out.println("通信三班");
    8. }
    9. }
    10. class GradeB implements GradeNameProvider{
    11. @Override
    12. public void gradeName() {
    13. System.out.println("通信四班");
    14. }
    15. }
    16. abstract class Application{
    17. abstract GradeNameProvider createGrade();
    18. public GradeNameProvider getGrade(){
    19. return createGrade();
    20. }
    21. }
    22. class ConCreateGradeA extends Application{
    23. @Override
    24. GradeNameProvider createGrade() {
    25. return new GradeA();
    26. }
    27. }
    28. class ConCreateGradeB extends Application{
    29. @Override
    30. GradeNameProvider createGrade() {
    31. return new GradeB();
    32. }
    33. }


  5. 我们测试一下工厂模式,代码如下

    1. class Test{
    2. public static void main(String[] args) {
    3. Application application = new ConCreateGradeA();
    4. GradeNameProvider grade = application.getGrade();
    5. grade.gradeName();
    6. }
    7. }


    抽象工厂模式

  • 抽象工厂模式,很抽象。。。但是不难
  • 规定好具体抽象,不同班级产线去实现相应的方法,互不干扰,切换班级只需new不同班级即可。
  • CommunicationClassFour这个班级没有我去实现,通信三班已经实现了,通信四班还不好实现吗?只需要实现具体业务的抽象方法即可。小伙伴们可以copy我下面的代码自己去实现一下通信四班
  • 抽象工厂更像是一个工具箱,想要什么东西拿什么,比如MybatisPlus支持很多DB一样,需要什么DB就new什么DB,底层去实现每个DB的逻辑

    public class AbstractFactory {

    1. public static void main(String[] args) {
    2. GradeUtils gradeUtils = new CommunicationClassThree();
    3. GradeName grade = gradeUtils.getGradeName();
    4. grade.grade();//这里是通信三班
    5. GradeStudentName gradeName = gradeUtils.getGradeStudentName();
    6. gradeName.name();//这里假装是一个通信三班班级的List
    7. }
    8. }
    9. interface GradeName{
    10. void grade();
    11. }
    12. class CommunicationClassThreeName implements GradeName{
    13. @Override
    14. public void grade() {
    15. System.out.println("这里是通信三班");
    16. }
    17. }
    18. interface GradeStudentName{
    19. void name();
    20. }
    21. class CommunicationClassThreeStudentName implements GradeStudentName{
    22. @Override
    23. public void name() {
    24. System.out.println("这里假装是一个通信三班班级的List");
    25. }
    26. }
    27. interface GradeUtils{
    28. GradeName getGradeName();
    29. GradeStudentName getGradeStudentName();
    30. }
    31. class CommunicationClassThree implements GradeUtils{
    32. @Override
    33. public GradeName getGradeName() {
    34. return new CommunicationClassThreeName();
    35. }
    36. @Override
    37. public GradeStudentName getGradeStudentName() {
    38. return new CommunicationClassThreeStudentName();
    39. }
    40. }