🚀🚀🚀尚硅谷传送门==>B站尚硅谷Java设计模式
❤❤❤感谢尚硅谷❤❤❤
🛴🛴🛴最近开始计划学习一下设计模式了,加油!!!
🚗简单工厂模式
从披萨店的案例引入工厂模式,进入学习
披萨的种类很多(比如 GreekPizza、CheesePizza 等)
- 披萨的制作有 prepare(准备材料工作),bake(烘烤工作), cut(切片工作), box(包装工作)
- 完成披萨店订购功能。
先分析传统思路
传统思路代码
披萨类Pizza
//将披萨类定义为抽象类;
public abstract class Pizza {
//披萨的种类名;
protected String name;
//制作披萨时准备原材料的工作;
public abstract void prepare();
//烘烤披萨;
public void bake() {
System.out.println(name + " 烘焙中...;");
}
//披萨切片;
public void cut() {
System.out.println(name + " 切片中.....;");
}
//披萨包装;
public void box() {
System.out.println(name + " 打包....;");
}
//为披萨设置种类名;
public void setName(String name) {
this.name = name;
}
}
奶酪披萨类CheesePizza
//奶酪披萨类;
public class CheesePizza extends Pizza{
@Override
public void prepare() {
setName("奶酪披萨");
System.out.println("奶酪披萨准备材料工作");
}
}
希腊披萨类GreekPizza
public class GreekPizza extends Pizza{
@Override
public void prepare() {
setName("希腊披萨");
System.out.println("希腊披萨准备工作");
}
}
订购披萨类ToOrderPizza
//订购披萨类;
public class ToOrderPizza {
//初始化时执行构造方法;
public ToOrderPizza() {
Pizza pizza = null;
//订购的种类;
String orderType;
do {
//动态获取订购披萨的种类;
orderType=gettype();
if(orderType.equals("CheesePizza")){
pizza=new CheesePizza();
}else if(orderType.equals("GreekPizza")){
pizza=new GreekPizza();
}else {
break;
}
//进行披萨的制作;
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
//输入台获取披萨的种类;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨种类:");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
披萨店PizzaShop
//披萨店类;
public class PizzaShop {
public static void main(String[] args) {
//订购披萨,完成工作;
new ToOrderPizza();
}
}
尝试使用;
输入订购的披萨种类:
CheesePizza
奶酪披萨准备材料工作
奶酪披萨 烘焙中...;
奶酪披萨 切片中.....;
奶酪披萨 打包....;
输入订购的披萨种类:
GreekPizza
希腊披萨准备工作
希腊披萨 烘焙中...;
希腊披萨 切片中.....;
希腊披萨 打包....;
输入订购的披萨种类:
qweqw
需要注意的是,如果需要增加另外的披萨种类时,就要去创建新的种类;然后在订购披萨时添加新的依赖;
这样的做法会导致依赖关系复杂;
违反了设计模式的OCP(开闭原则);[对扩展开放,对修改关闭]
引入简单工厂模式进行优化
简单工厂模式作为创建型模式,仅需要一个工厂对象去决定创建的是哪种披萨产品的实例对象即可.
引入一个简单工厂类将创建着各种个披萨实例对象进行封装;
所有的订购披萨类都在这个简单工厂类中创建对象;
保证了扩展新种类披萨后,只需要在简单工厂类中修改即可.
也去避免了在增加新的披萨种类后(即提供方扩展了新的功能/属性后;作为使用方的订购类完全不需要去考虑在自己的内部修改代码
);保证了开闭原则.
增加一个简单工厂类SimpleFactory
//使用简单工厂将创建披萨对象封装起来;
public class SimpleFactory {
//根据披萨的种类去提供披萨的对象实例;
public Pizza createPizza(String orderType){
Pizza pizza=null;
if(orderType.equals("CheesePizza")){
pizza=new CheesePizza();
}else if(orderType.equals("GreekPizza")){
pizza=new GreekPizza();
}
return pizza;
}
}
修改订购披萨类ToOrderPizza
//订购披萨类;
public class ToOrderPizza {
//定义简单工厂属性;
private SimpleFactory simpleFactory;
Pizza pizza=null;
//在初始化构造方法处就去设置简单工厂对象;
public ToOrderPizza(SimpleFactory simpleFactory) {
setSimpleFactory(simpleFactory);
}
//设置简单工厂对象;
public void setSimpleFactory(SimpleFactory simpleFactory) {
//用户输入披萨类型;
String orderType="";
//设置简单工厂对象;
this.simpleFactory = simpleFactory;
do {
//先获取披萨种类;
orderType = gettype();
//调用工厂对象的方法创建披萨对象;
pizza = this.simpleFactory.createPizza(orderType);
if(pizza!=null){
//披萨制作;
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("<----没有该种类披萨,订购失败---->");
break;
}
}while (true);
}
//获取披萨的种类;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨种类:");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
披萨店类调用订购类时,构造方法内传入简单工厂对象;
//披萨店类;
public class PizzaShop {
public static void main(String[] args) {
//订购披萨;
new ToOrderPizza(new SimpleFactory());
System.out.println("结束");
}
}
测试使用;
输入订购的披萨种类:
CheesePizza
奶酪披萨准备材料工作
奶酪披萨 烘焙中...;
奶酪披萨 切片中.....;
奶酪披萨 打包....;
输入订购的披萨种类:
GreekPizza
希腊披萨准备工作
希腊披萨 烘焙中...;
希腊披萨 切片中.....;
希腊披萨 打包....;
输入订购的披萨种类:
adsasdsa
<----没有该种类披萨,订购失败---->
结束
简单工厂模式,实际上也可以修改为静态工厂模式,
将简单工厂内的创建披萨对象方法设置为静态方法;
这样,在订购类中无需创建工厂对象即可调用方法;
简单静态工厂类;SimpleFactory
//使用简单工厂将创建披萨对象封装起来;
public class SimpleFactory {
//根据披萨的种类去提供披萨的对象实例;
public static Pizza createPizza(String orderType){
Pizza pizza=null;
if(orderType.equals("CheesePizza")){
pizza=new CheesePizza();
}else if(orderType.equals("GreekPizza")){
pizza=new GreekPizza();
}
return pizza;
}
}
订购披萨类ToOrderPizza
;
自然也就不需要去定义工厂类作为属性了;直接调用方法即可.
//订购披萨类;
public class ToOrderPizza {
Pizza pizza=null;
//定义披萨类型;
String orderType="";
//在初始化构造方法;
public ToOrderPizza() {
do {
//先获取披萨种类;
orderType = gettype();
//调用简单工厂的方法创建披萨对象;
pizza = SimpleFactory.createPizza(orderType);
if(pizza!=null){
//披萨制作;
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("<----没有该种类披萨,订购失败---->");
break;
}
}while (true);
}
//获取披萨的种类;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨种类:");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
披萨店类PizzaShop
//披萨店类;
public class PizzaShop {
public static void main(String[] args) {
//订购披萨,完成工作;
new ToOrderPizza();
System.out.println("结束");
}
}
🚗工厂方法模式
这时有一个新的需求,在点披萨的时候,还要考虑产地问题;
如果说,还用简单工厂模式解决的话,此时需要创建几个不同产地的简单工厂类(每个工厂类内部决定创建什么口味的披萨实例对象);
那么只要来个订购类;他就需要去聚合;项目的耦合过高,维护性差.
那么,引入工厂方法模式;让子类决定对象的实例化
而工厂方法模式是在工厂类中定义创建不同口味披萨对象的抽象方法;
然后让不同产地的子类继承这个工厂类;
不同产地的子类在实现方法时,依赖于不同口味的披萨对象.
案例代码;
披萨类Pizza
//将披萨类定义为抽象类;
public abstract class Pizza {
//披萨的种类名;
protected String name;
//制作披萨时准备原材料的工作;
public abstract void prepare();
//烘烤披萨;
public void bake() {
System.out.println(name + " 烘焙中...;");
}
//披萨切片;
public void cut() {
System.out.println(name + " 切片中.....;");
}
//披萨包装;
public void box() {
System.out.println(name + " 打包....;");
}
//为披萨设置种类名;
public void setName(String name) {
this.name = name;
}
}
北京生产的奶酪味披萨BJChessPizza
//北京生产的的奶酪味披萨
public class BJChessPizza extends Pizza{
@Override
public void prepare() {
setName("北京奶酪味披萨");
System.out.println("北京生产的奶酪味披萨准备工作==>;");
}
}
北京生产的胡椒味披萨BJPepperPizza
//北京生产的胡椒味披萨;
public class BJPepperPizza extends Pizza{
@Override
public void prepare() {
setName("北京胡椒味披萨");
System.out.println("北京生产的胡椒味披萨准备工作==>;");
}
}
伦敦生产的奶酪味披萨LDChessPizza
//伦敦生产的的奶酪味披萨
public class LDChessPizza extends Pizza{
@Override
public void prepare() {
setName("伦敦奶酪味披萨");
System.out.println("伦敦生产的奶酪味披萨准备工作==>;");
}
}
伦敦生产的胡椒味披萨LDPepperPizza
//伦敦生产的胡椒味披萨;
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
setName("伦敦胡椒味披萨");
System.out.println("伦敦生产的胡椒味披萨准备工作==>;");
}
}
订购披萨类ToOrderPizza
//订购披萨类;
public abstract class ToOrderPizza {
//定义根据披萨种类创建披萨对象的抽象方法
abstract Pizza createPizza(String orderType);
//在初始化构造方法;
public ToOrderPizza() {
Pizza pizza = null;
//定义披萨类型;
String orderType = "";
do {
//先获取披萨种类;
orderType = gettype();
//这里的方法由子类去实现;
pizza=createPizza(orderType);
if(pizza!=null) {
//披萨制作;
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("<----没有该种类披萨,订购失败---->");
break;
}
} while (true);
}
//获取披萨的种类;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨种类:");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
北京生产的订购披萨类BJOrderPizza
//北京产地的订购披萨;
public class BJOrderPizza extends ToOrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("chess")){
pizza = new BJChessPizza();
}else if(orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
伦敦生产的订购披萨类LDOrderPizza
//伦敦产地的订购披萨;
public class LDOrderPizza extends ToOrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("chess")){
pizza = new LDChessPizza();
}else if(orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
}
披萨店类PizzaShop
public class PizzaShop {
public static void main(String[] args) {
getPizza();
}
//选择产地;
public static void getPizza(){
PizzaShop pizzaShop=new PizzaShop();
String gettype = pizzaShop.gettype();
if(gettype.equals("北京")){
new BJOrderPizza();
}else if(gettype.equals("伦敦")){
new LDOrderPizza();
}else {
System.out.println("抱歉,暂时不提供该产地");
}
}
//输入选择生产地;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨产地(目前仅提供北京/伦敦):");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
测试使用
输入订购的披萨产地(目前仅提供北京/伦敦):
伦敦
输入订购的披萨种类:
chess
伦敦生产的奶酪味披萨准备工作==>;
伦敦奶酪味披萨 烘焙中...;
伦敦奶酪味披萨 切片中.....;
伦敦奶酪味披萨 打包....;
输入订购的披萨种类:
pepper
伦敦生产的胡椒味披萨准备工作==>;
伦敦胡椒味披萨 烘焙中...;
伦敦胡椒味披萨 切片中.....;
伦敦胡椒味披萨 打包....;
输入订购的披萨种类:
adsad
<----没有该种类披萨,订购失败---->
🚗抽象工厂模式
抽象工厂模式:定义了一个 接口 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式将简单工厂模式和工厂方法模式进行整合。
需要注意的是;在上一种抽象方法的案例中;要是多几个订购类呢;
后果就是让 (北京订购披萨,伦敦订购披萨) 都再去继承新增的订购类吗?
那么,是不是要来一个接口去管理管理这些上面的订购类呢,然后让 ( 北京订购披萨类,伦敦订购披萨类)去实现这个接口;
俗话说的好,最好的解决方式就是 “加一层”
大概类图如下
案例代码
披萨类Pizza
//将披萨类定义为抽象类;
public abstract class Pizza {
//披萨的种类名;
protected String name;
//制作披萨时准备原材料的工作;
public abstract void prepare();
//烘烤披萨;
public void bake() {
System.out.println(name + " 烘焙中...;");
}
//披萨切片;
public void cut() {
System.out.println(name + " 切片中.....;");
}
//披萨包装;
public void box() {
System.out.println(name + " 打包....;");
}
//为披萨设置种类名;
public void setName(String name) {
this.name = name;
}
}
北京生产的奶酪味披萨BJChessPizza
//北京生产的的奶酪味披萨
public class BJChessPizza extends Pizza{
@Override
public void prepare() {
setName("北京奶酪味披萨");
System.out.println("北京生产的奶酪味披萨准备工作==>;");
}
}
北京生产的胡椒味披萨BJPepperPizza
//北京生产的胡椒味披萨;
public class BJPepperPizza extends Pizza{
@Override
public void prepare() {
setName("北京胡椒味披萨");
System.out.println("北京生产的胡椒味披萨准备工作==>;");
}
}
伦敦生产的奶酪味披萨LDChessPizza
//伦敦生产的的奶酪味披萨
public class LDChessPizza extends Pizza{
@Override
public void prepare() {
setName("伦敦奶酪味披萨");
System.out.println("伦敦生产的奶酪味披萨准备工作==>;");
}
}
伦敦生产的胡椒味披萨LDPepperPizza
//伦敦生产的胡椒味披萨;
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
setName("伦敦胡椒味披萨");
System.out.println("伦敦生产的胡椒味披萨准备工作==>;");
}
}
抽象层工厂接口AbstractFactory
//抽象工厂模式;抽象层
public interface AbstractFactory {
//定义抽象方法; 根据口味类型 创建披萨实例对象;
public abstract Pizza createPizza(String orderType);
}
北京产地BJFactory
//北京产地;
public class BJFactory implements AbstractFactory{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("chess")){
pizza = new BJChessPizza();
}else if(orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
伦敦产地LDFactory
//伦敦产地;
public class LDFactory implements AbstractFactory{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("chess")){
pizza = new LDChessPizza();
}else if(orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
}
订购类ToOrderPizza
//订购披萨类;
public class ToOrderPizza {
//抽象工厂聚合
AbstractFactory abstractFactory;
private void setAbstractFactory(AbstractFactory abstractFactory) {
Pizza pizza=null;
String orderType="";
this.abstractFactory = abstractFactory;
do {
orderType=gettype();
pizza=abstractFactory.createPizza(orderType);
if(pizza!=null) {
//披萨制作;
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("<----没有该种类披萨,订购失败---->");
break;
}
}while (true);
}
//构造方法;
public ToOrderPizza(AbstractFactory abstractFactory){
setAbstractFactory(abstractFactory);
}
//获取披萨的种类;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨种类:");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
披萨店类PizzaShop
public class PizzaShop {
public static void main(String[] args) {
getPizza();
}
//选择产地;
public static void getPizza(){
PizzaShop pizzaShop=new PizzaShop();
String gettype = pizzaShop.gettype();
if(gettype.equals("北京")){
new ToOrderPizza(new BJFactory());
}else if(gettype.equals("伦敦")){
new ToOrderPizza(new LDFactory());
}else {
System.out.println("抱歉,暂时不提供该产地");
}
}
//输入选择生产地;
private String gettype() {
try {
BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入订购的披萨产地(目前仅提供北京/伦敦):");
String str = strs.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
测试
输入订购的披萨产地(目前仅提供北京/伦敦):
北京
输入订购的披萨种类:
chess
北京生产的奶酪味披萨准备工作==>;
北京奶酪味披萨 烘焙中...;
北京奶酪味披萨 切片中.....;
北京奶酪味披萨 打包....;
输入订购的披萨种类:
pepper
北京生产的胡椒味披萨准备工作==>;
北京胡椒味披萨 烘焙中...;
北京胡椒味披萨 切片中.....;
北京胡椒味披萨 打包....;
输入订购的披萨种类:
dasda
<----没有该种类披萨,订购失败---->
jdk中的工厂模式源码案例;
比如说日历类 Calendar
就用到了简单工厂模式
- 创建对象实例时,不要直接 new 类, 而是把这个new 类的动作放在一个工厂的方法中,并返回。
不要让类继承具体类
,而是继承抽象类或者是实现 接口- 不要重写基类中已实现的方法。