文章目录
- 0、案例:咖啡屋
- 1、简单工厂模式 + 静态工厂(不属于23种之列)
- 2、工厂方法模式
- 3、抽象工厂模式
- 4、建造者模式
- 5、原型设计模式
0、案例:咖啡屋
模拟咖啡店点餐。咖啡有多种,抽象类,子类为各种咖啡。咖啡店类聚合咖啡类。类图如下:
定义咖啡抽象类:
public abstract class Coffee {
//获取咖啡种类名称
public abstract String getName();
//加奶
public void addMilk() {
System.out.println("加奶");
}
//加糖
public void addSugar() {
System.out.println("加糖");
}
}
各种咖啡:
public class AmericanCoffee extends Coffee{
@Override
public String getName(){
return "美式";
}
}
public class LatteCoffee extends Coffee{
@Override
public String getName(){
return "拿铁";
}
}
咖啡屋类,聚合咖啡抽象类:
public class CoffeeStore {
public Coffee orderCoffee(String type) {
Coffee coffee = null;
if("americano".equals(type)) {
coffee = new AmericanoCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
} else {
throw new RuntimeException("店里没这种咖啡");
}
return coffee;
}
}
以上代码的缺陷是咖啡类和 + 咖啡屋内耦合太高。下面用工厂模式解耦合。
1、简单工厂模式 + 静态工厂(不属于23种之列)
即由一个工厂决定创建哪一种产品类型的实例。 包括:
抽象产品(抽象类)
具体产品(子类)
具体工厂(创建产品并提供方法给调用者)
改进上面的咖啡案例,引入工厂类,让咖啡屋不再自己创建咖啡对象,而是直接从工厂获取,类图:
/**
* 咖啡工厂类
*/
public class SimpleCoffeeFactory {
public Coffee createCoffee(String type) {
Coffee coffee = null;
if("americano".equals(type)) {
coffee = new AmericanoCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
}
return coffee;
}
}
//新的咖啡屋类
public class CoffeeStore {
public Coffee orderCoffee(String type) {
SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
Coffee coffee = factory.createCoffee(type);
//加配料
coffee.addMilk();
coffee.addsugar();
return coffee;
}
}
到这儿,有个疑惑,咖啡抽象类或子类变时,SimpleCoffeeFacroty类不还得变?这和直接咖啡屋类有啥区别?不都是改一个类?多此一举?其实不然,如果有一百家咖啡屋,而你没有工厂,那需求变更时你就得改一百次代码,而有了工厂,你只需改工厂一个类就行。本质还是这个工厂类带来了解耦。简单工厂可扩展为静态工厂(即把创建对象的方法改为静态的):
public class SimpleCoffeeFactory {
//静态的
public static Coffee createCoffee(String type) {
Coffee coffee = null;
if("americano".equals(type)) {
coffee = new AmericanoCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
}
return coffe;
}
}
但这种模式下,工厂类还是得修改,并不符合开闭原则。
2、工厂方法模式
- 定义一个接口或者一个抽象的工厂类,让它的实现类(也是一个工厂)来决定创建哪一个实例对象。
- 根据每个工厂不同的方法,来产生不同的所需要的对象
角色有:
抽象工厂:只提供创建产品的接口给外界调用
具体工厂:实现抽象工厂,完成具体产品的创建
- 抽象产品:咖啡类
- 具体产品:美式、拿铁
继续完善案例:
抽象工厂,只提供一个方法:
public interface CoffeeFactory {
Coffee createCoffee(); //生产咖啡对象
}
具体的工厂类,实现抽象工厂:美式咖啡工厂、拿铁咖啡工厂
//美式咖啡工厂,专门用来生产美式咖啡
public class LatteCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {
return new LatteCoffee();
}
}
//拿铁咖啡工厂,专门用来生产拿铁咖啡
public class AmericanCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
注意现在的咖啡店类:1)、它依赖于抽象,聚合的是抽象工厂对象 2)、创建咖啡店对象,需要set传一个咖啡工厂对象
public class CoffeeStore {
private CoffeeFactory factory;
//通过构造方法来赋值
public CoffeeStore(CoffeeFactory factory) {
this.factory = factory;
}
//也可set
public void setFactory(CoffeeFactory factory) {
this.factory = factory;
}
public Coffee orderCoffee(String type) {
Coffee coffee = factory.createCoffee(); //直接调抽象类的方法,到时是哪个子工厂,就能创建出哪种咖啡
//加配料
coffee.addMilk();
coffee.addsugar();
return coffee;
}
}
测试类:
public class Client {
public static void main(Stirng[] args) {
//创建咖啡店对象
CoffeeStore store = new CoffeeStore();
//创建具体的咖啡工厂
CoffeeFactory factory = new AmericanCoffeeFactory();
store.setFactory(factory);
//点咖啡
Coffee coffee = store.orderCoffee();
//获取咖啡名称
System.out.println(coffee.getName());
}
}
此时,再有新品种咖啡进来,只需新增代码NewCoffeeFactory去实现CoffeeFactory,以及新增Coffee的子类NewCoffee。测试类中自然就是:
//创建具体的咖啡工厂
CoffeeFactory factory = new NewCoffeeFactory();
store.setFactory(factory);
//....
符合开闭原则,并不会修改之前的代码。而缺点则是每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
3、抽象工厂模式
前面的工厂方法模式,生产的都是相同系列的对象,如Java课程、python课程。抽象工厂模式则是提供创建一系列相关或相互依赖对象的接口。比如生产汽车,将汽车分为车架、车门、底盘等各个零部件进行生产。
public interface CarFactory{
//获取车门对象
public CarDoor getCarDoor();
//获取车架对象
public CarFrame getCarFrame();
//获取底盘对象
public CarBasePlate getCarBasePlate();
//制作汽车
public void make();
}
//车门工厂
public abstract class CarDoorFactory{
public abstract void make();
}
//底盘工厂
public abstract class CarBasePlateFactory{
public abstract void make();
}
//车架工厂
public abstract class CarFrameFactory{
public abstract void make();
}
//车门
public class CarDoor extends CarDoorFactory{
@Override
public abstract void make(){
System.out.println("制作车门");
}
}
//底盘
public class CarBasePlate extends CarBasePlateFactory{
public abstract void make(){
System.out.println("制作车底盘");
}
}
//车架工厂
public class CarFrame extends CarFrameFactory{
public abstract void make(){
System.out.println("制作车架");
}
}
public class Car implements CarFactory{
private CarDoor carDoor = null;
private CarFrame carFrame = null;
private CarBasePlate carBasePlate = null;
@Override
public CarDoor getCarDoor(){
carDoor = new CarDoor();
return carDoor;
}
@Override
public CarFrame getCarFrame(){
carFrame = new new CarFrame();
return carFrame;
}
@Override
public CarBasePlate getCarBasePlate(){
carBasePlate = new CarBasePlate();
return carBasePlate;
}
@Override
public void make(){
carDoor.make();
carFrame.make();
carBasePlate.make();
System.out.print("小汽车制作完成");
}
}
测试:
public class Test{
public static void mian(STring[] args){
Car car = new Car();
car.getCarBasePlate();
car.getCarFrame();
car.getCarDoor();
car.make();
}
}
运行:
4、建造者模式
- 将复杂的对象的创建 和 属性赋值所分离
- 建造的过程和细节我们不需要知道,只需要通过构建者去进行操作
@Data
public class Car{
private String basePlate; //车底盘
private String frame; //车架
private String door; //车门
}
public abstract class Builder{
//车底盘
public abstract void buildBasePlate(String basePlate);
//车架
public abstract void buildCarFrame(String carFrame);
//车门
public abstract void buildCarDoor(String carDoor);
//制作车
public abstract Car makeCar();
}
写实现类:
public class CarBuilder extends Builder{
private Car car = new Car();
@Overrid
public abstract void buildBasePlate(String basePlate){
car.setBasePlate(basePlate);
}
@Override
public abstract void buildCarFrame(String carFrame){
car.setFrame(frame);
}
@Override
public abstract void buildCarDoor(String carDoor){
car.setDoor(carDoor);
}
@Override
public abstract Car makeCar(){
return this.car;
}
}
创建一个工程师:
public class Engineer{
private CarBuilder carBuilder;
//自动注入、构造方法、set方法都行,能完成赋值就行,这里写set
public void setCarBuilder(CarBuilder carBuilder){
this.carBuilder = carBuilder;
}
public Car mekeCar(String basePlate, String frame, String door){
carBuilder.buildBasePlate(basePlate);
carBuilder.buildCarFrame(frame);
carBuilder.buildCarDoor(door);
return carBuilder.makeCar();
}
}
测试:
public class Test{
public static void mian(STring[] args){
Engineer engineer = new Engineer();
CarBuilder carBuilder = new CarBuilder();
engineer.setCarBuilder(carBuilder);
Car car = engineer.makeCar("制作汽车底盘","制作汽车车架","制作汽车车门");
System.out.println(car);
}
}
运行:
5、原型设计模式
- 用于创建重复的对象,能够保证创建对象的性能
- 是创建对象的最佳方式
@Data
public class Pig{
private String name; //名字
private String doSomething; //喜欢做的事
}
现在要表示佩奇一家,正常创建流程如下:
public class Test{
public static void mian(STring[] args){
Pig peki = new Pig();
peki.setName("佩琪");
peki.setDoSomething("喜欢吃蛋糕");
System.out.println(peki);
Pig george = new Pig();
george.setName("乔治");
george.setDoSomething("喜欢睡觉");
System.out.println(george);
Pig pigDad = new Pig();
pigDad.setName("猪爸爸");
pigDad.setDoSomething("喜欢开车");
System.out.println(pigDad);
Pig pigMum = new Pig();
pigMum.setName("猪妈妈");
pigMum.setDoSomething("喜欢做饭");
System.out.println(pigMum);
}
}
运行:
采用原型设计模式后:实体类实现Cloneable接口
@Data
public class Pig implements Cloneable{
public Pig() {
System.out.println("小猪被初始化了...");
}
private String name; //名字
private String doSomething; //喜欢做的事
@Override
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
再次创建佩奇一家:
public class Test{
public static void mian(STring[] args){
Pig peki = new Pig(); //先new一个
peki.setName("佩琪");
peki.setDoSomething("喜欢吃蛋糕");
System.out.println(peki);
Pig george = (Pig) peki.clone(); //后面就克隆
george.setName("乔治"); //如果这里不赋值,那克隆出来的属性和克隆样本一样
george.setDoSomething("喜欢睡觉");
System.out.println(george);
Pig pigDad = (Pig) peki.clone() ;
pigDad.setName("猪爸爸");
pigDad.setDoSomething("喜欢开车");
System.out.println(pigDad);
Pig pigMum = (Pig) peki.clone() ;
pigMum.setName("猪妈妈");
pigMum.setDoSomething("喜欢做饭");
System.out.println(pigMum);
}
}
运行:
发现构造方法只被调用了一次,且出来的也照样是不同的对象。因此,当对象属性很多,而又要创建大量这种对象时,就可以用原型设计模式。该模式产生的对象,虽然都是不同的对象,单如果不重新赋值,属性却是与克隆样本保持一致的,即使是一个新的对象。