首页 文章 精选 留言 我的

精选列表

搜索[表单设计器],共10000篇文章
优秀的个人博客,低调大师

FlutterDojo设计之道——状态管理之路(二)

书接上回,我们讲到Flutter中同Page下跨Widget的数据管理。 第一种方案,我们使用ValueNotifier和ValueListenableBuilder来实现了。 这次,再介绍Flutter中的另一种数据管理方式——Notification。严格来说,Notification并不是一个跨Widget数据管理方案,它只完成了一半的功能,即Notification实现了数据状态修改的通知,但是需要监听的Widget收到通知后的处理,还是需要自己来实现的,这个实现,简单的说,可以是setState来重建UI,复杂了说,可以是配合其它任何一种数据管理/刷新的方案。 Notification Notification是Flutter中数据传递的一种机制。在Flutter的Widget树上,每个节点都可以发出Notification,Notification会沿着当前节点向上传递,所有的父节点都可以通过NotificationListener来监听Notification的改动。 Flutter中将这种由子节点向父节点传递Notification的机制称为通知冒泡(Notification Bubbling)。 Flutter中的很多地方使用了Notification,如Scrollable Widget在滑动时就会分发ScrollNotification,而Scrollbar正是通过监听ScrollNotification来确定滚动条位置的。 除了ScrollNotification,Flutter中还有KeepAliveNotification、SizeChangedLayoutNotification、LayoutChangedNotification等很多子类。 那么Notification为什么可以实现跨Widget的数据管理呢,首先,通过Notification机制有个使用条件,那就是父子关系,前面说了,父节点可以通过NotificationListener来监听子节点的Notification信息。所以借助Notification,可以很方便的从下至上传递数据的改变信息。 下面就通过一个系统的例子来演示下如何通过ScrollNotification,从滚动Widget拿到滚动数据。 classNotificationListenerWidgetextendsStatefulWidget{@override_NotificationListenerWidgetStatecreateState()=>_NotificationListenerWidgetState();}class_NotificationListenerWidgetStateextendsState<NotificationListenerWidget>{finalStreamController<String>_controller=StreamController();varstate='';@overridevoiddispose(){_controller.close();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnColumn(children:<Widget>[MainTitleWidget('NotificationListener基本使用'),Expanded(child:StreamBuilder(initialData:'',stream:_controller.stream,builder:(BuildContextcontext,AsyncSnapshot<String>snapshot){returnText(snapshot.data);},),),Expanded(child:NotificationListener<ScrollNotification>(child:ListView.builder(itemBuilder:(BuildContextcontext,intposition){returnListTile(title:Text('ListTile:$position'),);},itemCount:30,),onNotification:(notification){switch(notification.runtimeType){caseScrollStartNotification:state='开始滚动';break;caseScrollUpdateNotification:state='正在滚动';break;caseScrollEndNotification:state='滚动停止';break;caseOverscrollNotification:state='滚动到边界';break;}_controller.add('depth:${notification.depth}\n''state:$state\n''metrics\n''-axisDirection:${notification.metrics.axisDirection}\n''-axis:${notification.metrics.axis}\n''-extentAfter:${notification.metrics.extentAfter}\n''-extentBefore:${notification.metrics.extentBefore}\n''-extentInside:${notification.metrics.extentInside}\n''-minScrollExtent:${notification.metrics.minScrollExtent}\n''-maxScrollExtent:${notification.metrics.maxScrollExtent}\n''-atEdge:${notification.metrics.atEdge}\n''-outOfRange:${notification.metrics.outOfRange}\n''-pixels:${notification.metrics.pixels}\n''-viewportDimension:${notification.metrics.viewportDimension}\n');returnfalse;},),),],);}} 要获取滚动Widget的滚动数据,实际上就是在其父节点,通过NotificationListener来拿到其Notification改变的通知,NotificationListener可以指定接收Notification的具体类型,也可以在其内部通过runtimeType来进行判断,代码如下。 switch(notification.runtimeType){caseScrollStartNotification:print("开始滚动");break;caseScrollUpdateNotification:print("正在滚动");break;caseScrollEndNotification:print("滚动停止");break;caseOverscrollNotification:print("滚动到边界");break;} 不同的通知类型,实际上封装了不同的状态数据, 代码地址:Flutter Dojo-Widget-Scrolling-NotificationListener Notification的可取消性 由于Notification是沿着父节点向上查找,所以Notification在传递到每个父节点的时候,父节点都可以针对该Notification是否可以继续向上传递做出控制,源码如下所示。 所以,NotificationListener的onNotification回调是一个带bool返回值的函数,当返回false的时候,该Notification可以继续向上传递,否则则被该父节点拦截。 自定义Notification Flutter封装了很多Notification,同样也支持自定义Notification,这也是使用Notification来进行数据管理的核心原理。 自定义Notification非常简单,只需要继承Notification即可,代码如下所示。 classMyNotificationextendsNotification{MyNotification(this.msg);finalStringmsg;} 接下来,就是自己实现通知的分发。 classNotificationListenerWidgetextendsStatefulWidget{@override_NotificationListenerWidgetStatecreateState()=>_NotificationListenerWidgetState();}class_NotificationListenerWidgetStateextendsState<NotificationListenerWidget>{Stringmsg='';StringmsgParent='';boolreturnValue=true;@overrideWidgetbuild(BuildContextcontext){returnColumn(children:<Widget>[MainTitleWidget('自定义Notification'),SubtitleWidget('onNotification返回值控制通知的传递'),MultiSelectionWidget('onNotification返回值',[true,false],[true,false],(value){setState(()=>returnValue=value);}),NotificationListener<MyNotification>(onNotification:(notification){setState(()=>msgParent=notification.msg);returntrue;},child:NotificationListener<MyNotification>(onNotification:(notification){setState(()=>msg=notification.msg);returnreturnValue;},child:Column(children:[Text('自定义Msg:$msg,父Widget是否收到消息:${msgParent.isEmpty?false:true}'),Builder(builder:(BuildContextcontext){returnRaisedButton(onPressed:(){msg='';msgParent='';MyNotification('MyNotification').dispatch(context);},child:Text('Send'),);},),],),),),],);}} 代码地址:Flutter Dojo-Widget-Scrolling-NotificationListener 在使用自定义Notification的时候,需要注意几个地方。 继承Notification后,直接使用dispatch函数即可实现Notification的分发。 NotificationListener监听的是子节点,所以dispatch函数传入的context必须是子节点的Context,所以这里需要使用Builder来创建子节点的Context(创建新的Widget同样可以实现这个功能)。 要监听的Notification一定要是NotificationListener的child,原因前面已经说了。 修仙 Flutter Dojo开源至今,受到了很多Flutter学习者和爱好者的喜爱,也有越来越多的人加入到Flutter的学习中来,所以我建了个Flutter修仙群,但是人数太多,所以分成了【Flutter修仙指南】【Flutter修仙指北】【Flutter修仙指东】三个群,对Flutter感兴趣的朋友,可以留言。 项目地址: https://github.com/xuyisheng/flutter_dojo 本文分享自微信公众号 - Android群英传(android_heroes)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

FlutterDojo设计之道—状态管理之路(一)

Flutter万物皆Widget的理念很容易搭建出这样一个WidgetTree。 在这个Widget Tree中,通常会存在很多组件之间的相互依赖,时间一长,就很容易变成下面这样。 这是申明式编程的通病,因为Widget用于展示数据,而数据可能来源于很多其它的Widget,这时候跨Widget共享数据、传递数据,就变得很麻烦,而且不容易管理。 所以,Flutter在StatelessWidget、StatefulWidget的基础之上,还有一个InheritedWidget,专门用于进行数据、状态的共享与传递,除此之外,申明式编程独特的响应式架构,也通过观察者模式,让数据状态改变的监听变得比较容易,这些都是Flutter处理数据的优势。 下面的文章,将带领大家梳理Flutter中的数据流向,掌握Flutter的状态管理方案。 开篇 要管理Widget的数据、状态,首先要了解下,在Flutter中有哪些需要管理数据的场景。 一般来说,数据管理有两个场景: 同页面跨Widget数据管理 跨页面数据管理 Flutter在同一个Page中,可能存在很多的不同的Widget,这些Widget都在同一个Page层级之下,当某个Widget的状态发生改变之后,需要让其它Widget响应。 另外一种,就是多页面之间的数据共享。 那它们的区别是什么呢,在同一个Page下,所有的Widget与Page根Widget是可以形成父子关系的,因为通过PageRoute产生的新页面,其Page根Widget是挂载到App根Widget上的,多个Page之间的Widget,不存在父子关系。 首先,我们先来看下同页面跨Widget数据管理。 为了保证文章的完整性,本文会由浅入深,依次讲解Flutter中状态管理的方方面面,所以有些冗余的地方,请不要介意。 方案1-1 :StatefulWidget 这个相信大家都很了解了,StatefulWidget通过State来保存状态,当调用setState函数之后,整个StatefulWidget会重新执行build函数,从而使用全新的数据,生成新的Widget,这样看来,有了StatefulWidget之后,是不是就可以完全实现同页面的数据管理了呢? 的确可以,但是有个问题,如果页面里面有100个Widget,数据发生改变后,只有一个Widget需要接受这个改变,修改自己的UI,但是在这个StatefulWidget中,由于调用了setState函数,所以这个页面中的100个Widget都将执行重建,这显然是「家里有矿系列」,所以为了避免这个问题,就需要缩小StatefulWidget的范围,让setState函数控制的刷新,尽可能的范围小,这样当100个Widget中只有一个需要重建时,就不需要重新创建那99个不需要的Widget了。 但是新的问题又来了,StatefulWidget的范围小了,发生在这个StatefulWidget之外的数据改变,如何让这个StatefulWidget进行刷新呢?这时候,就需要利用到Flutter的响应式编程架构了。 方案1-2:ValueNotifier 从ValueNotifier的注释就能看明白,ValueNotifier实际上实现了一个观察者模式,ValueNotifier会持有一个Value对象,当Value对象发生改变时,即会通知到所有注册过的观察者。 A[ChangeNotifier]thatholdsasinglevalue.When[value]isreplacedwithsomethingthatisnotequaltotheoldvalueasevaluatedbytheequalityoperator==,thisclassnotifiesitslisteners. 那么借助ValueNotifier,就可以实现同Page内跨Widget的数据管理,将需要管理的数据托管给ValueNotifier,所有需要因为该数据而改变的Widget,都会注册监听,那么在数据发生改变时,ValueNotifier将自动通知到所有监听者,从而实现数据的管理。 下面这个例子,就演示了一个最简单的ValueNotifier的使用。 classValueNotifierWidgetextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){ValueNotifier<String>valueNotifier=ValueNotifier<String>('InitStringData');returnColumn(children:<Widget>[MainTitleWidget('ValueNotifier基本使用'),SubtitleWidget('在需要响应的Widget中addListener之后,一旦ValueNotifier的值发生改变,就会触发通知'),NotifierWidget(data:valueNotifier),RaisedButton(onPressed:()=>valueNotifier.value='NewValue${Random().nextInt(100)}',child:Text('Change'),),],);}}classNotifierWidgetextendsStatefulWidget{finalValueNotifier<String>data;NotifierWidget({this.data});@override_NotifierWidgetStatecreateState()=>_NotifierWidgetState();}class_NotifierWidgetStateextendsState<NotifierWidget>{Stringinfo;@overrideinitState(){super.initState();widget.data.addListener(changeNotifier);info='${widget.data.value}';}voidchangeNotifier(){setState(()=>info='${widget.data.value}');}@overrideWidgetbuild(BuildContextcontext){returnText(info,style:TextStyle(fontSize:30),);}@overridedispose(){widget.data.removeListener(changeNotifier);super.dispose();}} NotifierWidget注册了对ValueNotifier的监听,当Demo页面中的其它Widget触发了ValueNotifier的更新的时候(RaisedButton触发),NotifierWidget会自动接受到通知,从而刷新UI。 代码位置:Flutter Dojo-Widget-Async-ValueNotifier 自定义ValueNotifier ValueNotifier同样可以指定自定义类型,其原理与使用基础类型是一样的。 classValueNotifierWidgetextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){PersonNotifiercustomNotifier=PersonNotifier(People('xuyisheng',18));returnColumn(children:<Widget>[MainTitleWidget('CustomValueNotifier'),CustomNotifierWidget(data:customNotifier),RaisedButton(onPressed:()=>customNotifier.changePeopleName('zhujia'),child:Text('Change'),),],);}}classCustomNotifierWidgetextendsStatefulWidget{finalValueNotifier<People>data;CustomNotifierWidget({this.data});@override_CustomNotifierWidgetStatecreateState()=>_CustomNotifierWidgetState();}class_CustomNotifierWidgetStateextendsState<CustomNotifierWidget>{Peopleinfo;@overrideinitState(){super.initState();widget.data.addListener(changeNotifier);info=widget.data.value;}voidchangeNotifier(){setState(()=>info=widget.data.value);}@overrideWidgetbuild(BuildContextcontext){returnText('${info.name},${info.age}',style:TextStyle(fontSize:30),);}@overridedispose(){widget.data.removeListener(changeNotifier);super.dispose();}}classPeople{Stringname;intage;People(this.name,this.age);}classPersonNotifierextendsValueNotifier<People>{PersonNotifier(Peoplevalue):super(value);voidchangePeopleName(Stringname){value.name=name;notifyListeners();}} 同样是点击RaisedButton后,改变ValueNotifier.value的值,从而修改UI。 代码位置:Flutter Dojo-Widget-Async-ValueNotifier 通过ValueNotifier,我们将每个可能因为共享数据的变化而改变的Widget,封装起来,从而在数据改变的时候,只更新监听了该数据的Widget。 但是大家有没有发现,在使用ValueNotifier的时候,是有些冗余的,就好像前面用到的NotifierWidget,实际上大部分的ValueNotifier都需要这样配合使用,所以,Flutter也提供了这样一个类似的Widget——ValueListenableBuilder。 1-3:ValueListenableBuilder ValueListenableBuilder正是这样一个Widget,它封装了对ValueNotifier的使用,简化了其创建过程,Flutter Dojo的首页上,PageView和下面的进度条保存同步的过程,就是通过ValueListenableBuilder来实现的。 代码位置:Flutter Dojo-/pages/main/mainpage_scroll_container.dart ValueListenableBuilder的使用范式非常简单,即在多个创建修改、监听修改的Widget上,通过ValueNotifier来共享管理数据。 由于ValueListenableBuilder是一个StatefulWidget,所以它们的父Widget可以直接使用StatelessWidget来组织Widget,一个简单的示例如下所示。 classValueListenableBuilderWidgetextendsStatefulWidget{@override_ValueListenableBuilderWidgetStatecreateState()=>_ValueListenableBuilderWidgetState();}class_ValueListenableBuilderWidgetStateextendsState<ValueListenableBuilderWidget>{int_counter=0;finalValueNotifier<int>_notifier=ValueNotifier<int>(0);void_incrementCounter(){_counter++;_notifier.value++;}@overrideWidgetbuild(BuildContextcontext){returnColumn(children:<Widget>[MainTitleWidget('ValueListenableBuilder基本使用'),SubtitleWidget('修改数据时未调用setState,所以未通过ValueListenableBuilder管理的数据不会发生改变'),SizedBox(height:20),ValueListenableBuilder(valueListenable:_notifier,builder:(context,value,widget){returnText('ClickwithValueListenableBuilder$value');},),SizedBox(height:20),Text('ClickwithoutsetState$_counter'),SizedBox(height:20),RaisedButton(onPressed:(){_incrementCounter();},child:Text('Clickme'),),],);}} 代码位置:Flutter Dojo-Widget-Async-ValueListenableBuilder 修仙 Flutter Dojo开源至今,受到了很多Flutter学习者和爱好者的喜爱,也有越来越多的人加入到Flutter的学习中来,所以我建了个Flutter修仙群,但是人数太多,所以分成了【Flutter修仙指南】【Flutter修仙指北】【Flutter修仙指东】三个群,对Flutter感兴趣的朋友,可以添加我的微信,注明加入Flutter修仙群,或者直接关注我的微信公众号【Android群英传】。 感兴趣的朋友可以加我微信【Tomcat_xu】,我拉你入群。 项目地址: https://github.com/xuyisheng/flutter_dojo 本文分享自微信公众号 - Android群英传(android_heroes)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

JAVA设计模式(1)建造者模式

《2020年阿里云活动拼团》:https://www.aliyun.com/minisite/goods?userCode=czfmwdn3【限时】1年86元,3年229元,用来建站和编程学习【附WordPress建站教程】 1 定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 类型:创建类模式。 四个要素: 产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。在本类图中,产品类是一个具体的类,而非抽象类。实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。 抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现。这样更容易扩展。一般至少会有两个抽象方法,一个用来建造产品,一个是用来返回产品。 建造者:实现抽象类的所有未实现的方法,具体来说一般是两项任务:组建产品;返回组建好的产品。 导演类:负责调用适当的建造者来组建产品,导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。一般来说,导演类被用来封装程序中易变的部分。 2 代码实现 class Product { private String name; private String type; public void showProduct(){ System.out.println(“名称:”+name); System.out.println(“型号:”+type); } public void setName(String name) { this.name = name; } public void setType(String type) { this.type = type; } } abstract class Builder { public abstract void setPart(String arg1, String arg2); public abstract Product getProduct(); } class ConcreteBuilder extends Builder { private Product product = new Product(); public Product getProduct() { return product; } public void setPart(String arg1, String arg2) { product.setName(arg1); product.setType(arg2); } } public class Director { private Builder builder = new ConcreteBuilder(); public Product getAProduct(){ builder.setPart(“宝马汽车”,“X7”); return builder.getProduct(); } public Product getBProduct(){ builder.setPart(“奥迪汽车”,“Q5”); return builder.getProduct(); } } public class Client { public static void main(String[] args){ Director director = new Director(); Product product1 = director.getAProduct(); product1.showProduct(); Product product2 = director.getBProduct(); product2.showProduct(); } } 3 比较及总结 建造者模式的优点: 首先,建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。 其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。 建造者模式与工厂模式的区别: 建造者模式与工厂模式是极为相似的,总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色。在建造者模式的类图中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。 与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。 总结: 建造者模式与工厂模式类似,他们都是建造者模式,适用的场景也很相似。一般来说,如果产品的建造很复杂,那么请用工厂模式;如果产品的建造更复杂,那么请用建造者模式

优秀的个人博客,低调大师

Java描述设计模式(22):策略模式

本文源码:GitHub·点这里 || GitEE·点这里 一、生活场景 每年双十一,各大电商平台会推出不同的满减策略,当用户的消费金额满一定额度后,会进行减去一定的优惠额度,从而来一波清仓甩卖,使用策略模式来描述该流程。 public class C01_InScene { public static void main(String[] args) { // 选择满减策略,走相应的计算方式 FullReduce strategy = new Full100 (); Payment price = new Payment(strategy); double quote = price.payment(300); System.out.println("最终价格为:" + quote); } } /** * 付款 */ class Payment { private FullReduce fullReduce ; public Payment (FullReduce fullReduce){ this.fullReduce = fullReduce ; } public double payment (double totalPrice){ return this.fullReduce.getPayMoney(totalPrice) ; } } /** * 金额满减接口 */ interface FullReduce { double getPayMoney (double totalPrice) ; } /** * 不同的满减策略 */ class Full100 implements FullReduce { @Override public double getPayMoney(double totalPrice) { if (totalPrice >= 100){ totalPrice = totalPrice-20.0 ; } return totalPrice ; } } class Full500 implements FullReduce { @Override public double getPayMoney(double totalPrice) { if (totalPrice >= 500){ totalPrice = totalPrice-120.0 ; } return totalPrice ; } } 二、策略模式 1、基础概念 策略模式属于对象的行为模式。策略模式中定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客 户端。 2、模式图解 3、核心角色 环境角色 持有一个Strategy策略接口角色的引用。 抽象策略角色 通常由一个接口或抽象类实现。此角色给出所有的具体策略类要实现的接口。 具体策略角色 包装相关的算法或业务流程。 4、源码实现 public class C02_Strategy { public static void main(String[] args) { Strategy strategy = new ConcreteStrategyB() ; Context context = new Context(strategy) ; context.userMethod(); } } /** 环境角色类 */ class Context { //持有一个具体策略的对象 private Strategy strategy; /** * 构造函数,传入一个具体策略对象 * @param strategy 具体策略对象 */ public Context(Strategy strategy){ this.strategy = strategy; } public void userMethod (){ this.strategy.strategyMethod(); } } /** 抽象策略类 */ interface Strategy { // 策略方法 void strategyMethod () ; } /** 具体策略类 */ class ConcreteStrategyA implements Strategy { @Override public void strategyMethod() { System.out.println("策略A方法"); } } class ConcreteStrategyB implements Strategy { @Override public void strategyMethod() { System.out.println("策略B方法"); } } 三、策略模式总结 策略模式的关键是:变化的与不变分离,体现了“对修改关闭,对扩展开放”原则。客户端增加行为不用修改原有代码,只要添加一种策略即可,易于切换、易于理解、易于扩展。策略过多是会导致类数目庞大,变得难以维护。 四、源代码地址 GitHub·地址 https://github.com/cicadasmile/model-arithmetic-parent GitEE·地址 https://gitee.com/cicadasmile/model-arithmetic-parent

优秀的个人博客,低调大师

Java描述设计模式(21):状态模式

本文源码:GitHub·点这里 || GitEE·点这里 一、生活场景 1、场景描述 变色龙是爬行动物,是非常奇特的动物,它有适于树栖生活的种种特征和行为,身体也会随着环境的变化而变化出适应环境的颜色,非常神奇。下面基于状态模式对该变化过程进行描述。 2、代码实现 public class C01_InScene { public static void main(String[] args) { Chameleon chameleon = new Chameleon("红色","花丛环境") ; LifeContext lifeContext = new LifeContext() ; // 树叶环境 BodyColor bodyColor = new GreenColor (); lifeContext.setBodyColor(bodyColor); lifeContext.change(chameleon); // 树枝环境 bodyColor = new GrayColor() ; lifeContext.setBodyColor(bodyColor); lifeContext.change(chameleon); } } /** * 变色龙 */ class Chameleon { public String color ; public String contextDesc ; public Chameleon(String color, String contextDesc) { this.color = color; this.contextDesc = contextDesc; } } /** * 变色龙生存环境 */ class LifeContext { private BodyColor bodyColor; public void setBodyColor(BodyColor bodyColor) { this.bodyColor = bodyColor; } public void change (Chameleon chameleon){ bodyColor.change(chameleon) ; } } /** * 变色龙身体颜色抽象类 */ interface BodyColor { void change (Chameleon chameleon); } /** * 变色龙身体颜色具体类 */ class GreenColor implements BodyColor { @Override public void change(Chameleon chameleon) { System.out.println("变化前:"+chameleon.color+";"+chameleon.contextDesc); chameleon.contextDesc = "树叶环境" ; chameleon.color = "绿色" ; System.out.println("变化后:"+chameleon.color+";"+chameleon.contextDesc); } } class GrayColor implements BodyColor { @Override public void change(Chameleon chameleon) { System.out.println("变化前:"+chameleon.color+";"+chameleon.contextDesc); chameleon.contextDesc = "树枝环境" ; chameleon.color = "灰色" ; System.out.println("变化后:"+chameleon.color+";"+chameleon.contextDesc); } } 二、状态模式 1、基础概念 状态模式是对象的行为模式,状态模式允许一个对象在其内部状态改变的时候改变其行为。状态模式把对象的行为封装在不同状态的对象中,每一个状态对象都是抽象状态类的子类。意图是让一个对象在其内部状态改变的时候,其行为也随之改变。 2、模式图解 3、核心角色 环境角色 持有具体状态类的对象实例。这个具体状态类的实例给出此环境对象的现有状态。 抽象状态角色 定义一个接口,封装环境对象的状态所对应的行为。 具体状态角色 具体状态类实现了环境的状态所对应的行为。 4、源码实现 public class C02_State { public static void main(String[] args){ Context context = new Context(); State state = new ConcreteStateA() ; context.setState(state); context.printInfo("当前环境状态A"); state = new ConcreteStateB(); context.setState(state); context.printInfo("当前环境状态B"); } } /** * 环境角色 */ class Context { private State state; public void setState(State state) { this.state = state; } public void printInfo (String info) { state.stateInfo(info); } } /** * 抽象状态角色 */ interface State { void stateInfo (String param); } /** * 具体状态角色 */ class ConcreteStateA implements State { @Override public void stateInfo (String info) { System.out.println("ConcreteStateA:" + info); } } class ConcreteStateB implements State { @Override public void stateInfo (String info) { System.out.println("ConcreteStateB:" + info); } } 三、模式总结 将容易产生问题的if-else语句拆分,状态模式将每个状态的行为封装到对应的一个类中,代码有很强的可读性。 符合“开闭原则”,容易增删操作,管理状态。 会存在很多状态时。每个状态都要一个对应的类,会产生很多类,增加维护难度。 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,不同的状态有不同的行为,可以考虑使用状态模式。 四、源代码地址 GitHub·地址 https://github.com/cicadasmile/model-arithmetic-parent GitEE·地址 https://gitee.com/cicadasmile/model-arithmetic-parent

优秀的个人博客,低调大师

JAVA设计模式(2)建造者模式

1 定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 类型:创建类模式。 四个要素: 产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。在本类图中,产品类是一个具体的类,而非抽象类。实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。 抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现。这样更容易扩展。一般至少会有两个抽象方法,一个用来建造产品,一个是用来返回产品。 建造者:实现抽象类的所有未实现的方法,具体来说一般是两项任务:组建产品;返回组建好的产品。 导演类:负责调用适当的建造者来组建产品,导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。一般来说,导演类被用来封装程序中易变的部分。 2 代码实现 class Product { private String name; private String type; public void showProduct(){ System.out.println(“名称:”+name); System.out.println(“型号:”+type); } public void setName(String name) { this.name = name; } public void setType(String type) { this.type = type; } } abstract class Builder { public abstract void setPart(String arg1, String arg2); public abstract Product getProduct(); } class ConcreteBuilder extends Builder { private Product product = new Product(); public Product getProduct() { return product; } public void setPart(String arg1, String arg2) { product.setName(arg1); product.setType(arg2); } } public class Director { private Builder builder = new ConcreteBuilder(); public Product getAProduct(){ builder.setPart(“宝马汽车”,“X7”); return builder.getProduct(); } public Product getBProduct(){ builder.setPart(“奥迪汽车”,“Q5”); return builder.getProduct(); } } public class Client { public static void main(String[] args){ Director director = new Director(); Product product1 = director.getAProduct(); product1.showProduct(); Product product2 = director.getBProduct(); product2.showProduct(); } } 3 比较及总结 建造者模式的优点: 首先,建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。 其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。 建造者模式与工厂模式的区别: 建造者模式与工厂模式是极为相似的,总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色。在建造者模式的类图中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。 与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。 总结: 建造者模式与工厂模式类似,他们都是建造者模式,适用的场景也很相似。一般来说,如果产品的建造很复杂,那么请用工厂模式;如果产品的建造更复杂,那么请用建造者模式

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册