引言
今天我将以制作酸菜鱼谈谈java抽象思想和处理问题的思路,一方面分享酸菜鱼的制作步骤,另外一方面结合过程谈谈我联想到的设计模式和一些思想,随着编程经验的增加,再加上自己喜欢制作一些美食,越来越觉得编程思想都是来源于生活,抽象于生活,如果觉得可以请帮忙点赞、收藏、转发
我们先来看下整体流程:
整个制作过程真的简单,作为程序员的我们如果不知道吃什么,可以亲手实践下这道菜,接下我将详细叙述制作过程
一. 买鱼
1.选鱼
就近选择可靠的店,1人到2人建议选择2斤左右的,酸菜鱼制作我选择的是花鲢鱼,个人可根据口味和爱好选择喜欢的鱼,3人到5人建议选择3斤到4斤重的,我今天选择的是一般重的正好3斤,5人吃,还有其他菜,只吃鱼5人建议可以整2条3斤重的或者6斤重的,一般这种店都会售卖煮鱼调料,可以直接选择酸菜鱼调料,烹饪步骤也可按调料包说明进行操作,一般做出来味道都不错的,我这里直接选用的是酸菜包,也就3元一袋约200g酸菜
2.杀鱼
如果自身动手能力强,可以选择自己回家杀鱼并完成后面打整步骤,这里我们一般都是直接交给摊贩打理,摊贩将鱼拍晕,打鳞,破肚,清理内脏,清理鱼鳃,分解鱼头、鱼骨,切鱼片,打包装袋,我要求的是切片,摊贩会将带骨的和鱼片分开装袋,这个过程就是大家常谈的代理模式,我们将此项工作完全交给摊贩,在编程中我们也需要使用代理模式来完成某些需要的工作,接下来就摊贩帮我们处理鱼实现一下代理模式
定义接口,处理鱼
public interface HandleFish { /** * 处理鱼 * @param fish */ void handleFish(String fish); }
真实处理鱼的摊贩处理
@Service public class RealPersonHandleFish implements HandleFish{ /** * 处理鱼 * * @param fish */ @Override public void handleFish(String fish) { System.out.println("我是摊贩,开始处理:" + fish); } }
自己处理鱼
@Service public class MySelfHandleFist implements HandleFish { private RealPersonHandleFish realPersonHandleFish; /** * 处理鱼 * * @param fish */ @Override public void handleFish(String fish) { if (realPersonHandleFish == null) { realPersonHandleFish = new RealPersonHandleFish(); } System.out.println("开始处理:"); //调用其他类进行处理 realPersonHandleFish.handleFish(fish); } }
开始处理鱼
public class ProxyPatternDemo { public static void main(String[] args) { HandleFish handleFish = new MySelfHandleFist(); handleFish.handleFish("鱼"); } }
执行结果
开始处理: 我是摊贩,开始处理:鱼 Process finished with exit code 0
代理模式意图:为其他的对象提供一种代理,从而控制对这个对象的访问
代理模式主要解决:直接访问对象时带来的影响,比如说:要访问的对象在远程的机器上。
代理模式何时使用:访问一个类时,我们需要做一些控制的时候,不直接访问这个类,通过它的代理类进行访问。
代理模式如何解决:增加中间代理层。
代理模式关键代码:实现与被代理类组合,和被代理类具有同样的功能。
二. 清洗整理鱼肉,备好需要调料
1.清理鱼肉
尽管摊贩已经清洗过鱼肉,但可能有的摊贩打扫的不是那么令人满意,回家后务必自己重新清理干净,特别是鱼鳃(这个东西吃着是苦的,别问我怎么知道的),清理后将带骨的和鱼片分开装盆滤干水分,准备腌制
2.调料准备
今天煮酸菜鱼用到的调料基本上大家家里都有,具体可看上图调料工厂说明,胡椒粉建议家里可以备一瓶,买最小规格的,没有就不用,猪油能增加层次感,没有也可不用,还有就是去腥的料酒,少做饭的买个小规格的就好,大葱一般都可以不用,烹饪荤菜都少不了料酒,然后就是平常必备的那些了不一一赘述,其实我们所使用的调料,抽象一下就像我们平常使用的java基本数据类型以及集合类,每一样都会在我们的代码中使用,必不可少。注意1:生姜两用
- 切片 > 腌制时使用,给鱼肉去腥
- 直接拍(不用很细,只是把姜拍破) > 爆香烧汤,增加烫的味道
注意2:酸菜包,打开后用清水清洗1到2遍,挤干水分,然后切成大块
然后用锅开中火直接炒制酸菜,将多余的水分炒干后装盘备用,这样做的目的是为了炒制时能更加的激发酸菜的酸味和香味,怎么判断炒干 > 锅边无明显水分,炒制时无多余的水蒸气冒出
注意3:做啥菜都可以放点小葱,香菜根据个人口味放或不放
注意4:我这里没有选用现成的鱼调料,直接用少许火锅料(味道稍稍带点甜味,不辣),火锅料可根据个人口味选择,能吃辣的可以选择辣味重的,量大概就100g到300g足够了,直接用鱼调料包的按照说明操作即可
注意5:我使用了少量嫩肉粉,主要目的是适度增加鱼肉的爽滑口感,没有可以不用或者用少量淀粉替代
三. 腌制
鱼头鱼骨和鱼片分别用不同的容器腌制,腌制方法一致,腌制方法:放入适量的盐(不会就少一点少一点的慢慢增加,拌匀后直接尝,带有咸味稍重即可),盐是鱼肉入味的关键,盐少了烹饪出来的味道可能会很淡以至不好吃,然后放入少许胡椒粉,鸡精,料酒,嫩肉粉,姜片搅拌均匀,腌制时间不小于20分钟
四. 炒制汤料
- 放入食用油(我这里放的猪油和菜籽油)烧热
- 加入姜蒜(拍碎)大葱小火炒香
- 放入炒干的酸菜并加入少许食盐大火炒制20s到40s
- 加入火锅料,多一点花椒粒中火炒制30s左右
- 加入适量清水,淹没过鱼最好
五. 分时分段下入鱼肉
微信图片_2022080616250614.jpg
- 水烧开后中火煮1分钟然后先下入鱼头
- 过30s后下入带鱼骨的其他部分
- 煮2分钟后下入鱼片,让鱼片被烫淹没,再煮1分钟后捞出
六. 点缀装饰
出锅装盘后放上葱段和香菜
一份简单的酸菜鱼就制作完成,其实这个过程按照顺序一步一步操作就像是职责链模式
责任链模式
责任链模式(Chain of Responsibility Pattern),属于行为型模式,为请求创建了一个接收者对象的一条链。这种设计模式给予了请求的类型,对请求的发送端和接收端进行解耦操作。
在这种设计模式中,一般说来每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传递给下一个接收者,依此类推,知道这条链走完。
意图:
避免请求发送者与接收者强耦合在一起,让多个对象都有可能接收到请求,且将这些对象连接成一条链,沿着这条链持续传递请求,直到有对象处理它为止。
主要解决:
职责链上的每一个处理者负责处理请求,上游只需要将请求发送到职责链上即可,不用关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
何时使用:
在处理消息的时候以过滤很多道,比如权限校验的各个环节,参数,合法性校验等等。
如何解决:
拦截的类都实现统一接口。
关键代码:
Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
使用场景:
1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3、可动态指定一组对象处理请求。
简单实现:
我们创建抽象类 AbstractCookingFish,带有详细制作酸菜鱼步骤。然后我们创建六个顺序的处理类,都扩展了 AbstractCookingFish。每个处理类的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个处理类。
责任链模式的 UML 图
步骤 1
创建抽象的鱼处理类。
public abstract class AbstractCookingFish { public static final int FIRST = 1; public static final int SECOND = 2; public static final int THIRD = 3; public static final int FOURTH = 4; public static final int FIFTH = 5; public static final int SIXTH = 6; protected int level; protected AbstractCookingFish nextCookingFish; public void setNextCookingFish(AbstractCookingFish nextCookingFish){ this.nextCookingFish = nextCookingFish; } public void cookingFish(int level,String message){ if(this.level == level){ cooke(message); } if(nextCookingFish !=null){ nextCookingFish.cookingFish(level, message); } } abstract protected void cooke(String message); }
步骤 2
创建扩展了该鱼处理类的实体类。
public class BuyFish extends AbstractCookingFish { public BuyFish(int level){ this.level = level; } @Override protected void cooke(String message) { System.out.println("BuyFish:买鱼步骤--" + message); } }
public class CleanFish extends AbstractCookingFish { public CleanFish(int level){ this.level = level; } @Override protected void cooke(String message) { System.out.println("CleanFish:清理鱼,准备调料步骤--" + message); } }
public class PickleFish extends AbstractCookingFish { public PickleFish(int level){ this.level = level; } @Override protected void cooke(String message) { System.out.println("PickleFish:腌制鱼步骤--" + message); } }
public class CookedSoupFish extends AbstractCookingFish { public CookedSoupFish(int level){ this.level = level; } @Override protected void cooke(String message) { System.out.println("CookedSoupFish:炒制汤料步骤--" + message); } }
public class AddFish extends AbstractCookingFish { public AddFish(int level){ this.level = level; } @Override protected void cooke(String message) { System.out.println("AddFish:分时段加入鱼骨鱼肉步骤--" + message); } }
public class DecorateFish extends AbstractCookingFish { public DecorateFish(int level){ this.level = level; } @Override protected void cooke(String message) { System.out.println("最后一步DecorateFish:点缀装饰步骤--" + message); } }
步骤 3
创建不同类型的处理实现类。赋予它们不同的顺序,并在每个处理类中设置下一个处理类。每个处理类的下一个处理类代表的是链的一部分。
public class CookingFishDemo { private static AbstractCookingFish getCookingFish(){ AbstractCookingFish buyFish = new BuyFish(AbstractCookingFish.FIRST); AbstractCookingFish cleanFish = new CleanFish(AbstractCookingFish.SECOND); AbstractCookingFish pickleFish = new PickleFish(AbstractCookingFish.THIRD); AbstractCookingFish cookedSoupFish = new CookedSoupFish(AbstractCookingFish.FOURTH); AbstractCookingFish addFish = new AddFish(AbstractCookingFish.FIFTH); AbstractCookingFish decorateFish = new DecorateFish(AbstractCookingFish.SIXTH); buyFish.setNextCookingFish(cleanFish); cleanFish.setNextCookingFish(pickleFish); pickleFish.setNextCookingFish(cookedSoupFish); cookedSoupFish.setNextCookingFish(addFish); addFish.setNextCookingFish(decorateFish); return buyFish; } public static void main(String[] args) { AbstractCookingFish cookingFish = getCookingFish(); cookingFish.cookingFish(AbstractCookingFish.FIRST, "一"); cookingFish.cookingFish(AbstractCookingFish.SECOND, "二"); cookingFish.cookingFish(AbstractCookingFish.THIRD, "三"); cookingFish.cookingFish(AbstractCookingFish.FOURTH, "四"); cookingFish.cookingFish(AbstractCookingFish.FIFTH, "五"); cookingFish.cookingFish(AbstractCookingFish.SIXTH, "六"); } }
步骤 4
执行程序,输出结果:
Connected to the target VM, address: '127.0.0.1:55215', transport: 'socket' BuyFish:买鱼步骤--一 CleanFish:清理鱼,准备调料步骤--二 PickleFish:腌制鱼步骤--三 CookedSoupFish:炒制汤料步骤--四 AddFish:分时段加入鱼骨鱼肉步骤--五 最后一步DecorateFish:点缀装饰步骤--六 Disconnected from the target VM, address: '127.0.0.1:55215', transport: 'socket' Process finished with exit code 0
今天这个例子简单叙述了酸菜鱼的烹饪步骤,给大家讲述了设计模式中的代理模式和职责链模式,后期会随机更新其他设计模式,欢迎关注博主公众号,发现更多精彩内容!