Loading

设计模式--创建型模式

创建型模式

           创建型模式的作用就是创建对象,说到创建一个对象,最熟悉的就是 new 一个对象,然后 set 相关属性。但是,在很多场景下,我们需要给客户端提供更加友好的创建对象的方式,尤其是那种我们定义了类,但是需要提供给其他开发者用的时候。

工厂模式分为简单工厂模式,工厂模式,抽象工厂模式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。本质就是使用工厂方法代替new操作。

简单工厂模式

public class FoodFactory {
    public static Food makeFood(String name) {
        if (name.equals("兰州拉面")) {
            Food noodle = new LanZhouNoodle();
            System.out.println("兰州拉面"+noodle+"出锅啦");
            return noodle;
        } else if (name.equals("黄焖鸡")) {
            Food chicken = new HuangMenChicken();
            System.out.println("黄焖鸡"+ chicken +"出锅啦");
            return chicken;
        } else {
            System.out.println("不知道你做的什么哦~");
            return null;
        }
    }
}

其中,LanZhouNoodle 和 HuangMenChicken 都继承自 Food。

public class Cook {
    public static void main(String[] args) {
        Food food = FoodFactory.makeFood("黄焖鸡");
        FoodFactory.makeFood("jaja");
    }
}

简单地说,简单工厂模式通常就是这样,一个工厂类 XxxFactory,里面有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。

我们强调职责单一原则,一个类只提供一种功能,FoodFactory 的功能就是只要负责生产各种 Food。

在此例中可以看出,Cook 类在使用 FoodFactory 时就不需要 new 任何一个对象,这就是简单工厂模式的好处,封装了 new 的部分,做到的代码易用性。

工厂模式

简单工厂模式很简单,如果它能满足我们的需要,我觉得就不要折腾了。之所以需要引入工厂模式,是因为我们往往需要使用两个或两个以上的工厂,也就是有多个实际工厂,每个工厂用于返回这一类的实际对象

public interface FoodFactory {
    Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {
 
    @Override
    public Food makeFood(String name) {
        if (name.equals("A")) {
            return new ChineseFoodA();
        } else if (name.equals("B")) {
            return new ChineseFoodB();
        } else {
            return null;
        }
    }
}
public class AmericanFoodFactory implements FoodFactory {
 
    @Override
    public Food makeFood(String name) {
        if (name.equals("A")) {
            return new AmericanFoodA();
        } else if (name.equals("B")) {
            return new AmericanFoodB();
        } else {
            return null;
        }
    }
}

其中,ChineseFoodA、ChineseFoodB、AmericanFoodA、AmericanFoodB 都派生自 Food, 与此同时有两个工厂 ChineseFoodFactory 以及 AmericanFoodFactory 用于分别创建前面四种实例对象。

public class APP {
    public static void main(String[] args) {
        // 先选择一个具体的工厂
        FoodFactory factory = new ChineseFoodFactory();
        // 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
        Food food = factory.makeFood("A");
    }
}

虽然都是调用 makeFood("A") 制作 A 类食物,但是,不同的工厂生产出来的完全不一样。

第一步,我们需要选取合适的工厂,然后第二步基本上和简单工厂一样。

核心在于,我们需要在第一步选好我们需要的工厂。比如,我们有 LogFactory 接口,实现类有 FileLogFactory 和 KafkaLogFactory,分别对应将日志写入文件和写入 Kafka 中,显然,我们客户端第一步就需要决定到底要实例化 FileLogFactory 还是 KafkaLogFactory,这将决定之后的所有的操作。

抽象工厂模式

这个模式就是在工厂模式的基础上,进一步第一层的多个工厂进行抽象。

为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑实用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

抽象工厂一般由以下四个部分组成。

AbstractFactory 声明一个创建抽象产品对象的操作接口。

ConcreteFactory 实现创建具体产品对象的操作。

AbstractProduct 为一类产品对象声明一个接口。

ConcreteProduct 定义一个将被相应的具体工厂创建的产品对象。 实现AbstractProduct接口。

Client 仅使用由AbstractFactory和AbstractProduct类声明的接口

AbstractFactory:定义抽象工程类IAnimalFactory

抽象工厂包含抽象方法,需要被实例化。

package  com.pizilei.design.abstractfactory;
/**
*  这个接口就是类图中标识的
*  AbstractFactory抽象工厂
*  @author  pizilei
*
*/
public  interface  IAnimalFactory  {
    /**
      *  定义创建Icat接口实例的方法
      *  @return
      */
    ICat  createCat();
    /**
      *  定义创建IDog接口实例的方法
      *  @return
      */
    IDog  createDog();
}

ConcreteFactory创建抽象工厂类的两个实现类,WhiteAnimalFactoryBlackAnimalFactory

package  com.pizilei.design.abstractfactory;
/**
*  IAnimalFactory抽象工厂的实现类
*  @author  pizilei
*
*/
public  class  WhiteAnimalFactory  implements  IAnimalFactory  {
    @Override
    public  ICat  createCat()  {
          return  new  WhiteCat();
    }
    @Override
    public  IDog  createDog()  {
          return  new  WhiteDog();
    }
 
}
 
 
package  com.pizilei.design.abstractfactory;
/**
*  IAnimalFactory抽象工厂的实现类
*  @author  pizilei
*/
public  class  BlackAnimalFactory  implements  IAnimalFactory  {
    @Override
    public  ICat  createCat()  {
          return  new  BlackCat();
    }
    @Override
    public  IDog  createDog()  {
          return  new  BlackDog();
    }
 
}

AbstractProduct定义抽象工厂中要生产的抽象产品接口ICatIDog

package  com.pizilei.design.abstractfactory;
/**
*  类图中定义的AbstractProduct
*  指定工厂生产的产品
*  @author  pizilei
*
*/
public  interface  ICat  {
    /**
      *  定义方法
      */
    void  eat();
}
package  com.pizilei.design.abstractfactory;
/**
*  类图中定义的AbstractProduct
*  指定工厂生产的产品
*  @author  pizilei
*
*/
public  interface  IDog  {
 
    /**
      *  定义方法
      */
    void  eat();
}

ConcreteProduct创建产品的实现类BlackCatBlackDogWhiteCatWhiteDog

package  com.pizilei.design.abstractfactory;
/**
*  ICat接口的实现类
*  @author  pizilei
*
*/
public  class  BlackCat  implements  ICat  {
@Override
    public  void  eat()  {
          System.out.println("The  black  cat  is  eating!");
    }
}
 
 
package  com.pizilei.design.abstractfactory;
 
/**
*  IDog的实现类
*  @author  pizilei
*/
public  class  BlackDog  implements  IDog  {
@Override
    public  void  eat()  {
          System.out.println("The  black  dog  is  eating");
    }
}
 
 
package  com.pizilei.design.abstractfactory;
/**
*  ICat的实现类
*  @author  pizilei
*
*/
public  class  WhiteCat  implements  ICat  {
@Override
    public  void  eat()  {
          System.out.println("The  white  cat  is  eating!");
    }
}
package  com.pizilei.design.abstractfactory;
/**
*  IDog的实现类
*  @author  binghe
*
*/
public  class  WhiteDog  implements  IDog  {
@Override
    public  void  eat()  {
          System.out.println("The  white  dog  is  eating!");
    }
}

Client:定义一个测试类Test

 
/**
*  测试类
*  @author  pizilei
*
*/
public  class  Test  {
    public  static  void  main(String[]  args)  {
    IAnimalFactory  blackAnimalFactory  =  new  BlackAnimalFactory();
    ICat  blackCat  =  blackAnimalFactory.createCat();
    blackCat.eat();
    IDog  blackDog  =  blackAnimalFactory.createDog();
    blackDog.eat();
    
    IAnimalFactory  whiteAnimalFactory  =  new  WhiteAnimalFactory();
    ICat  whiteCat  =  whiteAnimalFactory.createCat();
    whiteCat.eat();
    IDog  whiteDog  =  whiteAnimalFactory.createDog();
    whiteDog.eat();
    }
}

由此可见,工厂方法确实为系统结构提供了非常灵活强大的动态扩展机制,只要我们更换一下具体的工厂方法,系统其他地方无需一点变换,就有可能将系统功能进行改头换面的变化

单例模式

简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。

getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。

特点:

  • 类构造器私有
  • 持有自己类型的属性
  • 对外提供获取实例的静态方法

饿汉式写法:

public class Singleton {  
   private static Singleton instance = new Singleton();   // 缺点 会提前生成这个对象 导致内存占用
   private Singleton (){}  
   public static Singleton getInstance() {  
   return instance;  
   }  
}

弊端:因为类加载的时候就会创建对象,所以有的时候还不需要使用对象,就会创建对象,造成内存的浪费

饱汉模式最容易出错:

public class Singleton {
    // 首先,也是先堵死 new Singleton() 这条路
    private Singleton() {}
    // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的
    private static volatile Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null) {
            // 加锁
            synchronized (Singleton.class) {
                // 这一次判断也是必须的,不然会有并发问题
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查,指的是两次检查 instance 是否为 null。

volatile 在这里是需要的,希望能引起读者的关注。

很多人不知道怎么写,直接就在 getInstance() 方法签名上加上 synchronized,这就不多说了,性能太差。

public class Singleton {
    private Singleton() {}
    // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
    private static class Holder {
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.instance;
    }
}

建造者模式

原型模式

posted @ 2022-12-16 21:59  aalanwyr  阅读(33)  评论(0编辑  收藏  举报