首页 > 其他分享 >设计模式

设计模式

时间:2023-06-02 16:34:16浏览次数:30  
标签:factory 披萨 System public 设计模式 class pizza

设计模式介绍

设计模式是程序员在面对同类软件工程设计问题所总结出来的有用经验,是某类问题的通用解决方案

作用:使程序(软件)具有更好:

  1. 代码重用性(即相同功能的代码,不用多次编写)
  2. 可读性(即编程规范性,便于其他程序员的阅读和理解)
  3. 可扩展性(即:当需要增加新的功能时,非常的方便,称为可维护)
  4. 可靠性(即当增加新的功能时,对原先的功能没有影响)
  5. 使程序呈现高内聚、低耦合的特性。

七大设计原则

设计模式原则就是程序员在编程时,应当遵守的原则,也是各种设计模式的基础(即:设计模式为什么这样设计的依据)。

设计模式常用的七大原则有:

单一职责原则 一个类应该只负责一项职责
接口隔离原则 一个类对另一个类的依赖应该建立在最小接口上
依赖倒转(倒置)原则 高层模块不应该依赖底层模块,二者都应该依赖抽象。
里氏替换原则 所有引用基类的地方必须能透明地使用其子类的对象
开闭原则 一个软件实体如类、模块和函数应该对扩展(提供方)开放,对修改(使用方)关闭
迪米特原则 一个类对自己依赖的类知道的越少越好
合成复用原则 尽量使用合成/聚合,而不是通过继承达到复用的目的。

单一职责原则

一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。当职责1需求变更
而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1,A2

作用:

  1. 降低类的复杂度,一个类只负责一项职责。
  2. 提高类的可读性,可维护性。
  3. 降低变更引起的风险。

接口隔离原则

客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上

应用实例

先看一张图:

img

上图中出现的问题:类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类D,如果接口Interface1对于类A和类C来说不是最小接口,那么类B和类D必须去实现他们不需要的方法。

按隔离原则应当这样处理:将接口Interface1拆分为独立的几个接口(这里我们拆分成3个接口),类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。如下类图

img

依赖倒转原则

依赖倒转原则(Dependence Inversion Principle)是指:

  1. 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  2. 抽象不应该依赖细节,细节应该依赖抽象
  3. 依赖倒转(倒置)的中心思想是面向接口编程
  4. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架
    构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类
  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

应用实例

方案1+分析说明

package com.atguigu.principle.inversion;

public class DependecyInversion {

	public static void main(String[] args) {
		Person person = new Person();
		person.receive(new Email());
	}

}


class Email {
	public String getInfo() {
		return "电子邮件信息: hello,world";
	}
}

//完成Person接收消息的功能
//方式1分析
//1. 简单,比较容易想到
//2. 如果我们获取的对象是 微信,短信等等,则新增类,同时Perons也要增加相应的接收方法
//3. 解决思路:引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖
//   因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就ok, 这样我们就符号依赖倒转原则
class Person {
	public void receive(Email email ) {
		System.out.println(email.getInfo());
	}
}

方案2(依赖倒转) +分析说明

package com.atguigu.principle.inversion.improve;

public class DependecyInversion {

	public static void main(String[] args) {
		//客户端无需改变
		Person person = new Person();
		person.receive(new Email());
		
		person.receive(new WeiXin());
	}

}

//定义接口
interface IReceiver {
	public String getInfo();
}

class Email implements IReceiver {
	public String getInfo() {
		return "电子邮件信息: hello,world";
	}
}

//增加微信
class WeiXin implements IReceiver {
	public String getInfo() {
		return "微信信息: hello,ok";
	}
}

//方式2
class Person {
	//这里我们是对接口的依赖
	public void receive(IReceiver receiver ) {
		System.out.println(receiver.getInfo());
	}
}

里氏替换原则

OO中的继承性的思考和说明

  • 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有
    的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
  • 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
  • 问题提出:在编程中,如何正确的使用继承? =>里氏替换原则

基本介绍

  • 里氏替换原则(Liskov Substitution Principle)在1988年,由麻省理工学院的以为姓里的女士提出的。
  • 如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象
  • 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
  • 里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖 来解决问题。

应用实例

package com.atguigu.principle.liskov;

public class Liskov {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a = new A();
		System.out.println("11-3=" + a.func1(11, 3));
		System.out.println("1-8=" + a.func1(1, 8));

		System.out.println("-----------------------");
		B b = new B();
		System.out.println("11-3=" + b.func1(11, 3));//这里本意是求出11-3
		System.out.println("1-8=" + b.func1(1, 8));// 1-8
		System.out.println("11+3+9=" + b.func2(11, 3));
		
		

	}

}

// A类
class A {
	// 返回两个数的差
	public int func1(int num1, int num2) {
		return num1 - num2;
	}
}

// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends A {
	//这里,重写了A类的方法, 可能是无意识
	public int func1(int a, int b) {
		return a + b;
	}

	public int func2(int a, int b) {
		return func1(a, b) + 9;
	}
}

问题:我们发现原来运行正常的相减功能发生了错误。原因就是类B无意中重写了父类的方法,造成原有功能出现错误。在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候
解决办法:通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。
改进方案:

img

package com.atguigu.principle.liskov.improve;

public class Liskov {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a = new A();
		System.out.println("11-3=" + a.func1(11, 3));
		System.out.println("1-8=" + a.func1(1, 8));

		System.out.println("-----------------------");
		B b = new B();
		//因为B类不再继承A类,因此调用者,不会再func1是求减法
		//调用完成的功能就会很明确
		System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3
		System.out.println("1+8=" + b.func1(1, 8));// 1+8
		System.out.println("11+3+9=" + b.func2(11, 3));
		
		
		//使用组合仍然可以使用到A类相关方法
		System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3
		

	}

}

//创建一个更加基础的基类
class Base {
	//把更加基础的方法和成员写到Base类
}

// A类
class A extends Base {
	// 返回两个数的差
	public int func1(int num1, int num2) {
		return num1 - num2;
	}
}

// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends Base {
	//如果B需要使用A类的方法,使用组合关系
	private A a = new A();

	//这里,重写了A类的方法, 可能是无意识
	public int func1(int a, int b) {
		return a + b;
	}

	public int func2(int a, int b) {
		return func1(a, b) + 9;
	}
	
	//我们仍然想使用A的方法
	public int func3(int a, int b) {
		return this.a.func1(a, b);
	}
}

开闭原则

一个软件实体如类、模块和函数应该对扩展(提供方)开放,对修改(使用方)关闭

迪米特原则

一个对象应该对其他对象保持最少的了解。又叫最少知道原则,即一个类对自己依赖的类知道的越少越好

尽量降低类与类的耦合。强调只和直接朋友(成员变量、方法参数、方法返回值)交流,不和陌生人(局部变量中的类)说话。

迪米特的特性是降低类的耦合,并不要求完全没有依赖关系。

合成复用原则

定义:尽量使用合成/聚合,而不是通过继承达到复用的目的

设计模式分类

设计模式分为三大类,总共有23种模式。具体分类:

  • 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂方法模式。
  • 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
  • 行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式(责任链模式)

23种设计模式详解

单例模式

单例模式:保证一个类只有一个实例,并提供唯一获取这个实例的入口

单例模式总的有八种:

  • 饿汉式(静态变量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(线程安全)
  • 懒汉式(线程安全,同步代码块)
  • 双重检测(DoubleCheck)
  • 静态内部类
  • 枚举

饿汉式(静态变量)

具体做法:

  1. 构造器私有化,防止外部创建对象
  2. 声明一个静态成员变量并创建相应的对象实例
  3. 对外提供一个静态公用方法获取这个对象

优点:线程安全,在类加载时就已经创建实例

缺点:如果创建的对象实例没有被用到,就会造成内存浪费。

结论:当保证对象会被使用到,可以使用这种方法

代码样例:

package signleton.type1;

public class SignletonTpye1 {
    //1.构造器私有化,防止外部创建对象
    //2.声明一个静态成员变量并创建相应的对象实例
    //3.对外提供一个静态公用方法获取这个对象
    private SignletonTpye1() {

    }

    private static final SignletonTpye1 instance = new SignletonTpye1();

    public static SignletonTpye1 getInstance() {
        return instance;
    }

}

饿汉式(静态代码块)

效果跟饿汉式静态常量一致,只不过创建的对象改在静态代码块创建。

代码样例:

package signleton.type1;

public class SignLetonType2 {
    private SignLetonType2() {

    }

    private static SignLetonType2 instance;
    static {
        instance = new SignLetonType2();
    }

    public static SignLetonType2 getInstance() {
        return instance;
    }
}

懒汉式(线程不安全)

优点:懒加载,不会浪费内存资源。

缺点:线程不安全

结论:不推荐使用

代码样例:

package signleton.type1;

public class SignLetonType3 {
    private SignLetonType3() {

    }

    private static SignLetonType3 instance;
    public static SignLetonType3 getInstance() {
        if(instance == null) {
            instance = new SignLetonType3();
        }
        return instance;
    }
}

懒汉式(线程安全)

优点:懒加载,线程安全

缺点:并发度低,可能会导致性能瓶颈

结论:不推荐使用

代码样例:

package signleton.type1;

public class SignletonType4 {
    private SignletonType4() {

    }
    private static SignletonType4 instance;
    public static synchronized SignletonType4 getInstance() {
        if(instance == null) {
            instance = new SignletonType4();
        }
        return instance;
    }
}

懒汉式(线程安全,同步代码块)

优点:懒加载

缺点:线程不安全

结论:不推荐使用

代码样例:

public class SignletonType5 {
    private SignletonType5() {

    }
    private static SignletonType5 instance;

    public static SignletonType5 getInstance() {
        if(instance == null) {
            synchronized (SignletonType5.class) {
                instance = new SignletonType5();
            }
        }
        return instance;
    }
}

双重检测(DoubleCheck)

即支持懒加载,又支持高并发,推荐使用。

代码样例:

package signleton.type1;

public class SignletonType6 {
    private SignletonType6() {

    }
    private static volatile SignletonType6 instance;

    public static SignletonType6 getInstance() {
        if(instance == null) {
            synchronized (SignletonType6.class) {
                if(instance == null) {
                    instance = new SignletonType6();
                }
            }
        }
        return instance;
    }
}

volatile的作用是禁止指令重排。instance = new SignletonType6()不是一个原子操作,在JVM至少分为三步:

  1. 给instance分配内存空间。
  2. 调用SignletonType6的构造函数实例化instance
  3. 将instance对象指向分配的内部空间(instance 就不是null)

2,3步的顺序不一定,可能顺序是1,3,2。那么这时使用instance这个实例对象就会有问题。

静态内部类

优点:线程安全,懒加载

结论:推荐使用

代码样例:

package signleton.type1;

public class SignletonType7 {
    private SignletonType7() {

    }

    private static class SignletonIntance {
        private static final SignletonType7 instance = new SignletonType7();
    }

    public static SignletonType7 getInstance() {
        return SignletonIntance.instance;
    }
}

利用了静态内部类的特点,当用到静态内部类时才会进行类加载,类加载时线程安全的。

枚举

使用枚举的特性保证实例的线程安全和唯一性。

代码样例:

package signleton.type1;

public enum SignletonType8 {
    instance;
    public void say() {
        System.out.println("to say...");
    }
}

JDK使用的单例模式

java.lang.Runtime使用的饿汉式(静态变量)单例模式。

工厂模式

工厂模式的核心思想就是将实例化的代码抽离出来,交由一个类统一管理和维护,进行解耦,提高可扩展性和维护性

背景引入

场景:采购披萨

  • 有CheesePizza(奶酪披萨)、GreekPizza(希腊披萨)
  • prepare(准备披萨)、bake(烘烤披萨)、cut(切披萨)、box(打包披萨)

原始实现方式

相关代码:

  • Pizza抽象类
package factory.simplefatory.pizza;

public abstract class Pizza {

    public abstract void prepare();

    public void bake() {
        System.out.println("烘烤披萨");
    }

    public void cut() {
        System.out.println("切披萨");
    }

    public void box() {
        System.out.println("打包披萨");
    }
}
  • CheesePizza
package factory.simplefatory.pizza;

public class CheesePizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("准备奶酪披萨原材料");
    }
}
  • GreekPizza
package factory.simplefatory.pizza;

public class GreekPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("准备希腊披萨原材料");
    }
}
  • OrderPizza(披萨下订单类)
package factory.simplefatory.order;

import factory.simplefatory.pizza.CheesePizza;
import factory.simplefatory.pizza.GreekPizza;
import factory.simplefatory.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class OrderPizza {
    OrderPizza() {
        Pizza pizza = null;
        while (true) {
            String orderType = getOrderType();
            if("cheese".equals(orderType)) {
                pizza = new CheesePizza();
            } else if("greek".equals(orderType)) {
                pizza = new GreekPizza();
            } else {
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
    }

    private String getOrderType() {
        InputStream in = System.in;
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println("请输入订购披萨类型");
        try {
            return bufferedReader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

类图如下:

img

问题:不利于扩展。如果现在新增一类披萨的话,使用者OrderPizza也要相应改变,OrderPizza有多个的话,影响的范围就太大了。

解决方法:OrderPizza不再创建披萨实例,将披萨实例的创建交由一个工厂类处理,后续如果有改动只需要改这个工厂就可以了。这就是简单工厂模式

简单工厂模式

简单工厂模式就是将子类对象的创建交由一个工厂类进行创建,不再让使用方进行子类的实例创建

相关代码:

  • NewPizza
package factory.simplefatory.pizza;

public class NewPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("准备新的种类披萨");
    }
}
  • PizzaFactory
package factory.simplefatory.pizza;

public class PizzaFactory {
    public static Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if("cheese".equals(orderType)) {
            pizza = new CheesePizza();
        } else if("greek".equals(orderType)) {
            pizza = new GreekPizza();
        } else if("new".equals(orderType)) {
            pizza = new NewPizza();
        }
        return pizza;
    }
}
  • OrderPizza
package factory.simplefatory.order;

import factory.simplefatory.pizza.CheesePizza;
import factory.simplefatory.pizza.GreekPizza;
import factory.simplefatory.pizza.Pizza;
import factory.simplefatory.pizza.PizzaFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class OrderPizza {
    OrderPizza() {
        Pizza pizza = null;
        while (true) {
            String orderType = getOrderType();
            pizza = PizzaFactory.createPizza(orderType);
            if(pizza == null) {
                System.out.println("没有你要的披萨");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
    }

    private String getOrderType() {
        InputStream in = System.in;
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println("请输入订购披萨类型");
        try {
            return bufferedReader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

类图如下:

img

可以看见OrderPizza直接依赖 PizzaFactory,由 PizzaFactory负责各类披萨实例的插件。这样就实现OrderPizza对披萨子类的解耦。

工厂方法模式

父类定义一个创建对象的抽象方法,由子类决定要实例化的类,对象的实例化推迟到子类

新需求:披萨除了种类不同,也区分地区,比如:北京、上海

相关代码:

  • 披萨类
package factory.fatorymethod.pizza;

public abstract class Pizza {

    public abstract void prepare();

    public void bake() {
        System.out.println("烘烤披萨");
    }

    public void cut() {
        System.out.println("切披萨");
    }

    public void box() {
        System.out.println("打包披萨");
    }
}

package factory.fatorymethod.pizza;


public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备北京奶酪披萨原材料");
    }
}

package factory.fatorymethod.pizza;


public class BJGreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备北京希腊披萨原材料");
    }
}

package factory.fatorymethod.pizza;


public class SHCheesePizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备上海奶酪披萨原材料");
    }
}

package factory.fatorymethod.pizza;


public class SHGreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备上海希腊披萨原材料");
    }
}
  • OrderPizza
package factory.fatorymethod.order;


import factory.fatorymethod.pizza.Pizza;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public abstract class OrderPizza {
    public abstract Pizza createPizza(String orderType);

    public String getOrderType() {
        InputStream in = System.in;
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println("请输入订购披萨类型");
        try {
            return bufferedReader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
  • BJOrderPizza
package factory.fatorymethod.order;

import factory.fatorymethod.pizza.BJCheesePizza;
import factory.fatorymethod.pizza.BJGreekPizza;
import factory.fatorymethod.pizza.Pizza;


public class BJOrderPizza extends OrderPizza{
    BJOrderPizza() {
        while (true) {
            String orderType = getOrderType();
            Pizza pizza = this.createPizza(orderType);
            if(pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("没有你要的披萨");
                break;
            }
        }
    }

    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if("cheese".equals(orderType)) {
            pizza = new BJCheesePizza();
        } else if("greek".equals(orderType)) {
            pizza = new BJGreekPizza();
        }
        return pizza;
    }
}
  • SHOrderPizza
package factory.fatorymethod.order;

import factory.fatorymethod.pizza.*;

public class SHOrderPizza extends OrderPizza{
    SHOrderPizza() {
        while (true) {
            String orderType = getOrderType();
            Pizza pizza = this.createPizza(orderType);
            if(pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("没有你要的披萨");
                break;
            }
        }
    }

    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if("cheese".equals(orderType)) {
            pizza = new SHCheesePizza();
        } else if("greek".equals(orderType)) {
            pizza = new SHGreekPizza();
        }
        return pizza;
    }
}

类图如下:

img

抽象工厂模式

定义一个父类工厂接口,定义创建实例的抽象方法,由子类工厂去实现

代码如下:

  • 披萨类
package factory.fatorymethod.pizza;

public abstract class Pizza {

    public abstract void prepare();

    public void bake() {
        System.out.println("烘烤披萨");
    }

    public void cut() {
        System.out.println("切披萨");
    }

    public void box() {
        System.out.println("打包披萨");
    }
}

package factory.fatorymethod.pizza;


public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备北京奶酪披萨原材料");
    }
}

package factory.fatorymethod.pizza;


public class BJGreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备北京希腊披萨原材料");
    }
}

package factory.fatorymethod.pizza;


public class SHCheesePizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备上海奶酪披萨原材料");
    }
}

package factory.fatorymethod.pizza;


public class SHGreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("准备上海希腊披萨原材料");
    }
}
  • PizzaFactory
package factory.absfactory.factory;

import factory.absfactory.pizza.Pizza;

public interface PizzaFactory {
    public abstract Pizza createPizza(String orderType);
}
  • BJPizzaFactory
package factory.absfactory.factory;


import factory.absfactory.pizza.BJCheesePizza;
import factory.absfactory.pizza.BJGreekPizza;
import factory.absfactory.pizza.Pizza;


public class BJPizzaFactory implements PizzaFactory {

    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if("cheese".equals(orderType)) {
            pizza = new BJCheesePizza();
        } else if("greek".equals(orderType)) {
            pizza = new BJGreekPizza();
        }
        return pizza;
    }
}
  • SHPizzaFactory
package factory.absfactory.factory;


import factory.absfactory.pizza.*;

public class SHPizzaFactory implements PizzaFactory {

    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if("cheese".equals(orderType)) {
            pizza = new SHCheesePizza();
        } else if("greek".equals(orderType)) {
            pizza = new SHGreekPizza();
        }
        return pizza;
    }
}
  • OrderPizza
package factory.absfactory.order;

import factory.absfactory.factory.PizzaFactory;
import factory.absfactory.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class OrderPizza {
    private PizzaFactory pizzaFactory;
    OrderPizza(PizzaFactory pizzaFactory) {
        this.pizzaFactory = pizzaFactory;
        while (true) {
            String orderType = this.getOrderType();
            Pizza pizza = pizzaFactory.createPizza(orderType);
            if(pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("没有你要的披萨");
                break;
            }
        }
    }
    public String getOrderType() {
        InputStream in = System.in;
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println("请输入订购披萨类型");
        try {
            return bufferedReader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
  • 测试类
public class Main {
    public static void main(String[] args) {
//        new OrderPizza(new BJPizzaFactory());
        new OrderPizza(new SHPizzaFactory());
    }
}

类图如下:

img

JDK使用的工厂模式

Calendar类使用简单工厂模式,Calendar的getInstance方法

装饰模式

代理模式

观察者模式

标签:factory,披萨,System,public,设计模式,class,pizza
From: https://www.cnblogs.com/1963942081zzx/p/17452178.html

相关文章

  • 设计模式小记
    创建型模式(CreationalPatterns):工厂模式(FactoryPattern):通过工厂方法创建对象,隐藏具体实现细节,例如创建不同类型的按钮。//简单工厂模式classButtonFactory{createButton(type){switch(type){case'submit':returnnewSubmitButton();......
  • 设计模式详解之抽象工厂模式--企业的运行模式
    前言本文主要讲述设计模式中的抽象工厂模式,文中使用通俗易懂的案例,使你更好的学习本章知识点并理解原理,做到有道无术。一.什么是抽象工厂模式抽象工厂是23种设计模式中创建型模式的一种,抽象工厂是由多个工厂组合而成。上一章我们提到的工厂模式只存在一个抽象角色,而抽象工厂是......
  • golang实现设计模式之享元模式总结-代码、优缺点、适用场景
    享元模式是一种结构型的设计模式,通过共享细粒度对象实现对象的复用,从而达到减少对象创建与销毁,减少内存消耗,其本质是本质是缓存共享对象,降低内存消耗。享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象......
  • Java设计模式之单例模式
    一、何谓单例模式?单例模式,也叫单子模式,是一种常用的软件设计模式,属于创建型模式的一种。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一......
  • javascript设计模式-责任链
    责任链可以用来消除请求的发送者和接收者之间的耦合,这是通过实现一个由隐式地对请求进行处理的对象组成的链而做到的。链中的每个对象可以处理请求,也可以将其传给下一个对象。JS内部就使用了这种模式来处一事件捕获和冒泡问题。一般的结构如下:发送者知道链中的第一个接收者,它向这个......
  • golang实现设计模式之构建者模式总结-代码、优缺点、适用场景
    构建者模式也是一种创建型的设计模式,该模式将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的对象。大白话就是,构建者模式,从输出角度看依然是创建个对象实例,但是构建者模式更关注创建的细节,或者说一个对象的创建可以拆分为多个步骤,所有的步骤完成才创建出这个对......
  • Go设计模式
    Go-设计模式整理参考:Go设计模式24-总结(更新完毕)-Mohuishou(lailin.xyz)go设计模式实现,包含23种常见的设计模式实现设计模式学习的重点是什么?设计原则,以及设计模式的使用场景和优缺点,实现相对来说还没有那么重要如果是常见的设计模式是武术招式,那么设计原则就是内......
  • Java 微服务中的聚合器设计模式示例
    微服务架构中的聚合器设计模式是一种设计模式,用于通过聚合多个独立的微服务的响应来组成一个复杂的服务。它也是与SAGA、CQRS和EventSourcing一起的基本微服务设计模式之一。当客户端请求需要跨多个微服务分布的数据或功能时,此模式是合适的。可以提高系统的性能和可扩展性通过允许......
  • 什么是微服务中的断路器设计模式?如何实施?
    大家好,微服务设计模式是Java开发人员需要学习的非常重要的概念,不仅是为了创建一个健壮的、可扩展的、高性能的微服务架构,也是为了在Java开发人员面试中取得好成绩。过去,我分享了几种微服务设计模式,如eEventSourcing、SAGA、DatabasePerMicroservices、CQRS、APIGateway......
  • golang实现设计模式之抽象工厂模式总结-代码、优缺点、适用场景
    抽象工厂模式也是一种创建型的设计模式,其是在工厂模式的基础上实现更高程度的内聚。我们知道在工厂模式中,一种产品类就需要新建个对应的工厂类生成产品的实例,这会有什么问题呢?虽然工厂模式解决了简单工厂模式不好扩展的问题,实现了OCP,但一种产品就需要新建一个工厂类,比如有10000种......