阿里云服务器怎么玩才能更有意思?

怎样玩才有意思,这个因人而异,主要看你的云服务器用来做什么,如果仅是用来试验测试学习的,那云服务器的玩法可多了,我初步列了一下,就有以下这么多种玩法:

1、 基于 CentOS 搭建微信小程序服务教程;

2、 搭建微信 AI 机器人;

3、 基于CentOS搭建微信订阅号后台服务;

4、 基于 CentOS 搭建 Discuz 论坛;

5、 基于 CentOS 搭建 WordPress 个人博客;

6、 基于 CentOS 搭建 FTP 文件服务;

7、 基于 CentOS 搭建个人网盘;

8、 搭建个人 Leanote 云笔记本;

9、 搭建 Git 服务器;

10、 搭建 SVN 服务器;

11、 搭建 Node.js 环境;

12、 搭建 Docker 环境;

13、 搭建邮件服务;

14、 搭建 ShowDoc 文档工具;

15、 搭建 Python 开发环境;

16、 搭建 PySpider 爬虫服务;

17、 搭建 Hadoop 伪分布式环境;

18、 搭建基于 ZIPKIN 的数据追踪系统;

19、 搭建基于 HDFS 碎片文件存储服务;

20、 搭建 .NET Core 开发环境;

21、 搭建 Mono 开发环境;

22、 基于 CentOS 7 搭建 GitLab;

23、 基于 Ubuntu + nextCloud 搭建自己的私人网盘

解决提交项目到GitHub时,出现报错问题

解决提交项目到GitHub,报错Please tell me who you are的问题

描述:

在*次提交项目到GitHub时,出现了以下问题

%title插图%num

看了一下错误原因:Run git config –global user.email “[email protected]” git config –global user.name ”

原来是Git没有配置全局用户的原因

 

解决方案:

找到Git安装目录下的Git Bash,运行后输入下面两行代码即可

(备注:这里的name and email,*好还是输入注册GitHub时的name and email,因为这里决定了你往GitHub提交代码之后,是否能够获得贡献值)

git config --global user.email "[email protected]"  
git config --global user.name "Your Name"

%title插图%num

 

扩展:

以上方法配置的是全局的用户名和邮箱,如果没有单独为某个项目进行配置的话,那么所有提交的项目都将使用全局的用户名和邮箱。

单独为项目配置的方法如下:

(备注:采用就近原则,当同时设置全局用户名/邮箱,和单独为项目配置用户名/邮箱时,会默认使用单独为项目配置的用户名/邮箱)

1、进入到本地项目目录,找到隐藏文件夹.git

2、进入该文件夹下,找到config文件

3、在该文件下,添加以下代码

[user]
    name = XXX
    email = XXXX

 

前端 css+js实现网页中的【返回顶部】功能

描述:

本文主要是讲,通过css+js实现网页中的【返回顶部】功能。

 

实现代码:

HTML:

1 <div>
2     <button onclick="returnTop()" id="btnTop" title="返回顶部">返回顶部</button>
3 </div>

 

CSS:

 

 1 /* return top */
 2 #btnTop {
 3   display: none;
 4   position: fixed;
 5   bottom: 20px;
 6   right: 30px;
 7   z-index: 99;
 8   border: none;
 9   outline: none;
10   background-color: #89cff0;
11   color: white;
12   cursor: pointer;
13   padding: 15px;
14   border-radius: 10px;
15 }
16 #btnTop:hover {
17   background-color: #1E90FF;
18 }

 

 

JS:

 1 // 当网页向下滑动 20px 出现"返回顶部" 按钮
 2 window.onscroll = function() {
 3     scrollFunction()
 4 };
 5  
 6 function scrollFunction() {
 7     console.log(121);
 8     if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
 9         document.getElementById("btnTop").style.display = "block";
10     } else {
11         document.getElementById("btnTop").style.display = "none";
12     }
13 }
14  
15 // 点击按钮,返回顶部
16 function returnTop() {
17     document.body.scrollTop = 0;
18     document.documentElement.scrollTop = 0;
19 }

Android 的 Bitmap 转 base64 给到 H5, H5 不能直接渲染这个 Base64 吗?

h5 渲染:data:image/png;base64,base64 编码的 png 图片数据

h5 渲染 base64 编码的图片需要的是不是一定得是文件转出的 Base64 ?
而 Android 中的 Bitmap 中按格式存储的是每一个像素点的 16 进制颜色值,所以这并不是个文件转出来的 base64 也不是浏览器可识别的么
如此理解十分浅薄啊,望双端大佬指教

4 条回复    2021-01-26 13:33:34 +08:00
oxromantic
    1

oxromantic   72 天前 via iPhone

喂,首先要符合你写的 image/png 格式啊
kop1989
    2

kop1989   72 天前

你也说了,html 中 img 标签需要先声明 data 的格式:image/png
然后你给了一个 bitmap 对象的 base64String,这和你声明的格式不符。(确实 bitmap 也不是 img 标签支持的格式)
kop1989
    3

kop1989   72 天前

所以你需要:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);

btw,手写的,所以不严谨。领会大意即可。

xhpan10
    4

xhpan10   72 天前

bitmap 没有压缩,不会很大吗,内存不会爆了?

小米钱包开通了米 pay,名下的二类虚拟卡怎么注销?

几年前用小米钱包开通了米 pay,绑定了工商银行卡。 *近去注销工商卡的时候,银行告知卡下面存在二类虚拟卡,无法注销。 找客服联系,*后开卡行电话告知,他们也没办法,需要我去小米钱包先注销虚拟卡。

但之前登陆小米的手机和手机都号已经不使用了,密码还记得,登录时需要验证码… 走小米的账号申述渠道,需要手持身份证不是很乐意给。 请问还有其他渠道可以注销银行卡吗?

第 1 条附言  ·  

小米这二类卡比较特殊,工商的 app 和工商的自助操作机都看不到的。 (微信生成的二类卡可以在工商 app 看到)。柜台也注销不了(小哥看起来挺专业的,也折腾了半小时各种尝试,*终失败了)
第 2 条附言  ·  

搞定,去了分行柜台,直接就可以消了,都不需要态度强硬。
一共去了 2 次柜台,打了 3 次客服电话,终于消掉这卡了
13 条回复    2021-01-27 09:15:41 +08:00
nolo
    1

nolo   72 天前

二类卡是可以柜台注销的。直接告知注销二类卡,不用说是小米虚拟卡。
mitong3269
    2

mitong3269   72 天前 via iPhone

去工商不能直接注销? 工商银行 app 我注销过二类卡
wsycqyz
    3

wsycqyz   72 天前

这个 bug 都没有测出来,小米工程师出来挨打
zpxshl
    4

zpxshl   72 天前

@mitong3269
@nolo
小米这二类卡比较特殊,工商的 app 是看不到的。 (微信生成的二类卡可以在工商看到)。柜台也注销不了(小哥看起来挺专业的,也折腾了半小时各种尝试,*终失败了)
mitong3269
    5

mitong3269   72 天前 via iPhone

@zpxshl 额 我注销的就是微信二类卡
overLoads
    6

overLoads   72 天前

同工行。自己一类卡别人开个个啥理财产品,不是我本人开的,二类卡就知道个号,然后手机号早就换了,去柜台,说要俩东西才能注销。
我拿了本人身份证和杭州市民卡(本人在上海),成功注销。
alfchin
    7

alfchin   72 天前 via iPhone

这是工行的问题啊
正常虚拟卡发卡行有*终决定权,并且有义务直接应客户要求注销。
小米钱包那边爱弄不弄
zpxshl
    8

zpxshl   71 天前 via Android

@alfchin 我也是这样觉得的,所以这锅没给小米
jim9606
    9

jim9606   71 天前

小米钱包貌似有包含两个机构。我在招行的快捷支付找到两个相关的。Mi Pay 用的是一闪通(这个貌似是没有支付机构参与的,等于直接向发卡行申请了一张虚拟借记卡)。

另一个显示是小米钱包的其实对应的是现在貌似分家的天星金融(主体是捷付睿通股份有限公司),也就是钱包 APP 里搞理财现金贷的机构。以前用小米的模拟门卡需要绑卡实名认证,事实上是要求开通天星金融的快捷支付。

如果楼主有办法把虚拟卡的卡号查出来,说不定有办法给你注销。

jim9606
    10

jim9606   71 天前

我刚才试了一下,天星金融绑卡会在实体卡下增加一个与“捷付睿通”的快捷支付协议。开通 MI Pay 会增加一张类别为“其他”且拥有全新卡号的银行卡,可以在 MI Pay 上删除也可以在工行 APP 删除。验证了我上面的说法。
zpxshl
    11

zpxshl   71 天前 via Android

@jim9606 感谢答复。 虚拟卡号,工行客服无法查到,我准备明天去柜台查询,应该可以。
我用小米的时候还没有天星金融。米 pay 我确实开通过。但我在工行 app,网页均查不到对应二类卡(通过微信开通的工行二类卡可以在 app 查到)
Doracis
    12

Doracis   71 天前

去柜台注销,肯定能注销掉,我是 12306 在中国银行下加了一张虚拟二类卡,也是去柜台注销的,如果柜员不了解这种业务你可以试试去当地总行那种大的银行,亲身经验,*对能注销掉,而且这种二类卡注销业务只能在银行办理,要么按你说的手持身份证人工申诉,要么就是去银行注销
zpxshl
    13

zpxshl   71 天前 via Android

@Doracis 感谢。 我准备换家支行,再不行就去分行

iOS 23种设计模式

设计模式主要分三个类型:创建型、结构型和行为型。 
其中创建型有: 
    一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点 
    二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。 
    三、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。 
    四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。 
    五、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。 
行为型有: 
    六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。 
    七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。 
    八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。 
    九、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。 
    十、State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。 
    十一、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。 
    十二、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系 
    十三、Mediator,中介者模式:用一个中介对象封装一些列的对象交互。 
    十四、Visitor,访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。 
    十五、Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 
    十六、Memento,备忘录模式:在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。 
结构型有: 
    十七、Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。 
    十八、Facade,外观模式:为子系统中的一组接口提供一致的界面,fa?ade提供了一高层接口,这个接口使得子系统更容易使用。 
    十九、Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问 
    二十、Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。 
    二十一、Decrator,装饰模式:动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。 
    二十二、Bridge,桥模式:将抽象部分与它的实现部分相分离,使他们可以独立的变化。 
    二十三、Flyweight,享元模式



<span style="word-wrap: normal; word-break: normal; line-height: 21px;"><br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;"><strong><span style="word-wrap: normal; word-break: normal; line-height: 21px; color: rgb(0, 0, 153);">设计模式</span></strong>(Design Pattern),是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;">使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己、于他人、于系统都是多赢的,设计模式使代码编制真正工程化。设计模式是软件工程的基石,如同大厦的一块块砖石一样<span style="word-wrap: normal; word-break: normal;">使代码编制真正工程化</span>。</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;"><span style="word-wrap: normal; word-break: normal; line-height: 26px; font-family: Arial;">只有精通了设计模式,才敢说真正理解了软件工程。可以说,设计模式是每一个架构师所必备的技能之一。</span></span>作为一个面向对象设计程序员,只有精通了设计模式,才能摆脱码奴的命运,成为一个真正的软件工程师,才能完成自身价值的飞跃和设计思想的升华!



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;">
</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;">
</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;"><strong>1、设计模式和框架</strong></span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;"><span style="word-wrap: normal; word-break: normal; line-height: 24px;">  可复用面向对象软件系统现在一般划分为两大类:应用程序工具箱和</span><span style="word-wrap: normal; word-break: normal; line-height: 24px;">框架</span><span style="word-wrap: normal; word-break: normal; line-height: 24px;">(Framework),我们平时开发的具体软件都是应用程序,Java的API属于工具箱;而框架是构成一类特定软件可复用设计的一组相互协作的类,EJB(Enterprise Java Beans)是Java应用于企业计算的框架。</span></span>



<span style="word-wrap: normal; word-break: normal; line-height: 24px; font-family: arial, 宋体, sans-serif;">  框架通常定义了应用体系的整体结构类和对象的关系等等设计参数,以便于具体应用实现者能集中精力于应用本身的特定细节。框架主要记录软件应用中共同的设计决策,框架强调设计复用,因此框架设计中必然要使用设计模式。</span><span style="word-wrap: normal; word-break: normal; line-height: 24px; font-family: arial, 宋体, sans-serif;"> 
 另外,设计模式有助于对框架结构的理解,成熟的框架通常使用了多种设计模式,如果你熟悉这些设计模式,毫无疑问,你将迅速掌握框架的结构,我们一般开发
者如果突然接触EJBJ2EE等框架,会觉得特别难学,难掌握,那么转而先掌握设计模式,无疑是给了你剖析EJB或J2EE系统的一把利器。</span>

<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;">
</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;">
</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;"><strong>2、设计模式的原则</strong></span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
<span style="word-wrap: normal; word-break: normal; line-height: 25px; font-family: arial, 宋体, sans-serif;"><span style="word-wrap: normal; word-break: normal; line-height: 24px;">近年来,大家都开始注意设计模式。那么,到底我们为什么要用设计模式呢?</span></span><span style="word-wrap: normal; word-break: normal; line-height: 24px; font-family: arial, 宋体, sans-serif;">为什么要提倡<span style="word-wrap: normal; word-break: normal;">设计模式</span>呢?</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; line-height: 26px; font-family: Arial;" />
<span style="word-wrap: normal; word-break: normal; line-height: 24px; font-family: arial, 宋体, sans-serif;">根本原因是为了摆脱编程低效率,提高代码复用,增强代码健壮稳定,增加可维护性。</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; line-height: 26px; font-family: Arial;" />
<span style="word-wrap: normal; word-break: normal; line-height: 24px; font-family: arial, 宋体, sans-serif;">
</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; line-height: 26px; font-family: Arial;" />
<span style="word-wrap: normal; word-break: normal; line-height: 24px; font-family: arial, 宋体, sans-serif;">那怎么才能实现代码复用呢?</span>



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
从
面向过程到面向对象,是软件设计诞生以来的迈出的*伟大的一步,面向对象程序设计成功解决了面向过程软件编程的低效率问题,并且彻底改变了人们的编程思
维,为软件设计揭开了新的篇章。然而,要实现面向对象设计,彻底摆脱面向过程设计思维,并不仅仅是只要使用了一门面向对象的编程语言就能够达到的。使用面
向对象设计,可以设计出优秀的软件,同样也可以设计出糟糕的软件。只有遵循一些特定的原则,才能设计出复用性高灵活性好的软件来。



<br style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; line-height: 26px;" />
在运用面向对象的思想进行软件设计时,需要遵循的原则一共有 6 条:


</span>
  1. 单一职责原则(Single Responsibility Principle)
  2. 里氏替换原则(Liskov Substitution Principle)
  3. 依赖倒置原则(Dependence Inversion Principle)
  4. 接口隔离原则(Interface Segregation Principle)
  5. 迪米特法则(Law Of Demeter)
  6. 开闭原则(Open Close Principle)
        在软件设计的过程中,只要我们尽量遵循以上六条设计原则,设计出来的软件才会是一个优秀的软件,它必定足够健壮、足够稳定,并以*大的灵活性来迎接随时而来的需求变更等因素。 3、设计模式的四要素   设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。

  • 模式名称(pattern name)
   一个助记名,它用一两个词来描述模式的问题、解决方案和效果。命名一个新的模式增加了我们的设计词汇。设计模式允许我们在较高的抽象层次上进行设计。基 于一个模式词汇表,我们自己以及同事之间就可以讨论模式并在编写文档时使用它们。模式名可以帮助我们思考,便于我们与其他人交流设计思想及设计结果。找到 恰当的模式名也是我们设计模式编目工作的难点之一。

  • 问题(problem)
  描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。

  • 解决方案(solution)
  描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象组合)来解决这个问题。

  • 效果(consequences)
  描述了模式应用的效果及使用模式应权衡的问题。尽管我们描述设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性、扩充性或可移植性的影响,显式地列出这些效果对理解和评价这些模式很有帮助。 4、设计模式分类概览 《设计模式》一书,第 1 次将设计模式提升到理论高度,并将之规范化。书中一共总结了23种基本的设计模式,《设计模式》下载 这23种设计模式,几乎涵盖了面向对象设计过程中所有问题的解决方案,书中提到的23种设计模式分别是:

设计模式

(Design Pattern)

创建型

(Creational)

结构型

(Structural)

行为型

(Behavioral)

1、Abstract Factory(抽象工厂)

2、Builder(建造者)

3、Factory Method(工厂方法)

4、Prototype(原型)

5、Singleton(单态)

6、Adapter(适配器)

7、Bridge(桥模式)

8、Composite(组合)

9、Decorator(装饰)

10、Façade(外观)

11、Flyweight(享元)

12、Proxy(代理)

13、Chain of Responsibility(职责链)

14、Command(命令)

15、Interpreter(解释器)

16、Iterator(迭代器)

17、Mediator(中介)

18、Memento(备忘录)

19、Observer(观察者)

20、State(状态)

21、Strategy(策略)

22、Template Method(模板方法)

23、Visitor(访问者)

5、设计模式的设计场景 那么如此多的设计模式又是从何而来呢? 《易经》有云:“易有太*,是生两仪,两仪生四象,四象生八卦”,意思就是说世界万物皆有起源。 设计模式的起源,是面向对象程序设计思想,是面向对象设计的精髓——抽象。面向对象通过类和对象来实现抽象,实现时产生了面向对象的三个重要机制:封装、继承、多态,正是这三个机制衍生出了各种各样的设计模式。

设计模式的支持设计

目的

设计模式

可变方面

创建

(Creational)

1、Abstract Factory

2、Builder

3、Factory Method

4、Prototype

5、Singleton

产品对象家族

如何创建一个组合对象

被实例化的子类

被实例化的类

一个类的唯一实例

结构

(Structural)

6、Adapter

7、Bridge

8、Composite

9、Decorator

10、Façade

11、Flyweight

12、Proxy

对象的接口

对象的实现

一个对象的结构和组成

对象的职责,不生成子类

一个子系统的接口

对象的存储开销

如何访问一个对象,该对象的位置

行为

(Behavioral)

13、Chain of Responsibility

14、Command

15、Interpreter

16、Iterator

17、Mediator

18、Memento

19、Observer

20、State

21、Strategy

22、Template Method

23、Visitor

满足一个请求的对象

何时、怎样满足一个请求

一个语言的文法和解释

如何遍历、访问一个聚合的各元素

对象间如何交互、与谁交互

一个对象中哪些私有信息存放在该对象之外,以及在什么时候进行存储

多个对象依赖于另外一个对象,而这些对象又如何保持一致

对象的状态

算法设计

算法中的某些步骤

某些可作用于一个(组)对象上的操作,但不修改这些对象的类

6、设计模式的分类描述 设计模式,分为创建型模式、结构型模式、行为型模式

设计模式的分类描述

创建型模式

1.抽象工厂模式

为一个产品族提供了统一的创建接口。当需要这个产品族的某一系列的时候,可以从抽象工厂中选出相应的系列创建一个具体的工厂类。

2.建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

3.工厂方法模式

定义一个接口用于创建对象,但是让子类决定初始化哪个类。工厂方法把一个类的初始化下放到子类。

4.原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

5.单例模式

确保一个类只有一个实例,并提供对该实例的全局访问。

5.多例模式

确保一个类只有命名的实例,并提供对这些实例的全局访问。

对象池模式

通过回收利用对象避免获取和释放资源所需的昂贵成本。

惰性初始模式

推迟对象的创建、数据的计算等需要耗费较多资源的操作,只有在*次访问的时候才执行。

资源获取为初始化

通过绑定到合适对象的生命周期来确保资源被适当地释放。

结构型模式

6.适配器模式

将某个类的接口转换成客户端期望的另一个接口表示。适配器模式可以消除由于接口不匹配所造成的类兼容性问题。

7.桥接模式

将一个抽象与实现解耦,以便两者可以独立的变化。

8.组合模式

把多个对象组成树状结构来表示局部与整体,这样用户可以一样的对待单个对象和对象的组合。

9.装饰模式

向某个对象动态地添加更多的功能。修饰模式是除类继承外另一种扩展功能的方法。

10.外观模式

为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

11.享元

通过共享以便有效的支持大量小颗粒对象。

12.代理

为其他对象提供一个代理以控制对这个对象的访问。

行为型模式

13.职责链

为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。

14.命令

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。

15.解释器

给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。

16.迭代器

提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。

17.中介者

包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。

18.备忘录

备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

19.观察者模式

在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新。

20.状态

让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。

21.策略

定义一个算法的系列,将其各个分装,并且使他们有交互性。策略模式使得算法在用户使用的时候能独立的改变。

22.模板方法

模板方法模式准备一个抽象类,将部分逻辑以具体方法及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先构建一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

23.访问者

封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。

空对象

通过提供默认对象来避免空引用。

黑板

广义的观察者在系统范围内交流信息,允许多位读者和写者。

规格

以布尔形式表示的可重绑定的商业逻辑。

在面向对象软件设计的发展过程中,除了《设计模式》一书中提到的23中设计模式之外,新的设计模式仍然不断出现。 若想更进一步了解关于面向对象设计的背景,参考接口模式、内聚、耦合。 若想更进一步了解关于面向对象编程的背景,参考继承,重载,多态,接口

国内手机能媲美 apple 推送体验的是哪个?

作为 android 开发,一般我们都会集成常见的厂商通道,所以理论上

  • 华为
  • 小米
  • OPPO
  • vivo

都是可以的。不知道各位大佬真实使用的体验怎样?

 

73 条回复    2021-01-29 16:22:08 +08:00
maxmak
    1

maxmak   72 天前   ❤️ 3

一个能打的都没有
fromzero
    2

fromzero   72 天前

@maxmak 阁下是什么手机?
kangyan
    3

kangyan   72 天前   ❤️ 8

并没有和苹果相提并论的
oreoiot
    4

oreoiot   72 天前 via iPhone

国内之前在搞一个叫统一推送联盟的东西,搞起来了么?还有一个叫绿色应用联盟的,网页直接被微信 ban 了,笑

http://www.chinaupa.com

fromzero
    5

fromzero   72 天前

@oreoiot 那个只能看看,现在已经没声了。推送牵扯的利益太多。
maxmak
    6

maxmak   72 天前

@fromzero iPhone
dingyx99
    7

dingyx99   72 天前   ❤️ 1

媲美?你还是高估了,腾讯全系都是自己玩,这么久都如此(除了之前看 QQ 适配了一个 HMS 的消息推送,微信老早有一个 Firebase Message 也不是给国内用户的)
7gugu
    8

7gugu   72 天前

华为比较好,*近 QQ 和微信都接入了。Telegram 在华为上的推送也很顶,不挂 * 都能被推送到。
echo314
    9

echo314   72 天前   ❤️ 2

统一推送联盟就是个笑话,这类事就只能强制接入统一接口,就算没有立法,至少应该有部门法规(工信部),就算只是国内的统一接口。
像苹果谷歌是因为强制了应用商店所以相当一并强制了推送通道。
fromzero
    10

fromzero   72 天前

@7gugu 这么 6 我心动了。看看华为手机
S179276SP
    11

S179276SP   72 天前

@7gugu 你的手机上的 TG 是用了 Google fcm 吧
toptyloo
    12

toptyloo   72 天前 via Android

目前华为推送的覆盖远不如小米
tomari
    13

tomari   72 天前

不太行,还得等 google
WebKit
    14

WebKit   72 天前 via Android

*好的应该是小米了,覆盖率高,至于说 tg 那个是 fcm 只要有 google 套件的都可以,不用*的。
deplives
    15

deplives   72 天前 via iPhone

摸到脚后跟也叫媲美?
Cielsky
    16

Cielsky   72 天前 via Android

媲美没有。
*好的事小米吧。
不过 QQ,Tim 适配了华为的。
剩下的是其他。
ronman
    17

ronman   72 天前 via Android

@7gugu 微信这个恶心逼啥时候接入了?你记错了吧,只有 QQ
philipjf
    18

philipjf   72 天前   ❤️ 5

一个能打的都没有,但是能厚着脸皮坚持碰瓷苹果的只有牢厂
daozhihun
    19

daozhihun   72 天前 via Android

都不咋样,比如你用 outlook 收邮件 teams 办公,你看看哪个能收到消息提示
phdh71
    20

phdh71   72 天前 via iPhone

我觉得你是在碰瓷
qiangmin
    21

qiangmin   72 天前

目前小米的 mipush 是*好的,原生系统刷机党都是能翻就用 google 的,不能翻用小米的 mipush 。
但是,mipush 和 iOS 还是有明显的差距。
skylancer
    22

skylancer   72 天前 via iPhone

对,然而还是有没接的
虽然数量不多就是
ybbswc
    23

ybbswc   72 天前

推送是我用 iPhone 的*主要原因(大于 50%)。
S179276SP
    24

S179276SP   72 天前

@daozhihun outlook 可以使用手机自带的邮件,设置账户里可以添加 “公司” office 365,可以及时收邮件。
AndyAO
    25

AndyAO   72 天前   ❤️ 7

去谷歌上搜索’统一推送联盟’,大多数比较正规的消息都以正面为主,统一推送联盟自己的官方网站上的,就有很多的进展,如果说不相信官方的说法,可以看少数派这类*客媒体的说法,当然你也可以说这类媒体也不靠谱,那看看维基百科吧,谁也能编辑,但上面已经明确显示,去年就已经有了比较可喜的进展,大多数的手机品牌其实已经逐步介入这类服务.

![少数派]( https://cdn.jsdelivr.net/gh/Andy-AO/GitHubPictureBed/img/20210126082711.png)

![维基百科]( https://cdn.jsdelivr.net/gh/Andy-AO/GitHubPictureBed/img/20210126082627.png)

给出信息的时候,*好能够说明信息的具体来源,只是随口说一句,跟随其他人吆喝,那是什么也证明不了的

leafre
    26

leafre   72 天前 via iPhone

小米 苹果 双持,其他不知道,小米推送还是不行
madpecker009
    27

madpecker009   72 天前

小米用户表示微信不开后台收不到消息 QQ 也是。。阿里系和头条系的推送倒是挺管用的
DarlinW
    28

DarlinW   72 天前 via Android

@madpecker009 微信 QQ 长年给自启动权限就问题不大。
bubuyu
    29

bubuyu   72 天前

@oreoiot 喷了,这个域名竟然没有备案。
HenryWang0723
    30

HenryWang0723   72 天前

小米苹果双持,讲道理这个推送问题是上了 V2EX 才知道的,自己完全没感觉
elevioux
    31

elevioux   72 天前   ❤️ 1

推送我是能关就关的,不是必须立刻知道的东西统统关掉,看着烦。关不掉的系统屏蔽整个 app 的通知。

所以我用啥都没区别。

learningman
    32

learningman   72 天前 via Android

@ronman 微信有 FCM 的,不过要折腾
RudyS
    33

RudyS   72 天前

一个能打的都没有
matolv
    34

matolv   72 天前

miui EU 版本使用 FCM 推送,FCM 未被 GFW block
WebKit
    35

WebKit   72 天前 via Android

@AndyAO 统一推送联盟,现在好像一加跟 ov 有接入,其他手机没怎么用不知道
CodeCodeStudy
    36

CodeCodeStudy   72 天前   ❤️ 8

为什么要推送,每天叮叮当当地响,不烦吗?我除了微信、QQ 、邮箱等少数有时效性的应用,大多数都是关闭通知的。
icemaple
    37

icemaple   72 天前   ❤️ 2

@CodeCodeStudy
为什么要推送,每天叮叮当当地响,不烦吗?
我除了微信、QQ 、邮箱等少数有时效性的应用,大多数都是关闭通知的。

没十年相关经验都说不出这两句话

xpp6541478
    38

xpp6541478   72 天前

非杠勿喷。没用过苹果手机,所以想问问 apple 推送体验比安卓的优秀在哪些方面?翻了所有人的回复好像都默认了 apple 推送体验优秀这个点。
bruce0
    39

bruce0   72 天前

@xpp6541478 简单说 只要给了 app 推送权限,这个 app 完全退出了(这样说不太严谨,苹果本来也没有后台运行这一说法),照样可以收到消息

Android 没有统一推送,需要 app 一直在后台运行, 才能收到推送消息,这样有两个问题
1. app 一直在后台,耗电,占内存,手机内存小的话,容易卡
2. app 后台被杀了, 就收不到消息了

上述两个问题,苹果都不存在,因为苹果上所有 app 都使用苹果的统一推送

yinzhili
    40

yinzhili   72 天前

@CodeCodeStudy 是的,还是看个人习惯,除了微信 QQ 和短信,我都把其它 app 的推送全关了。
juded
    41

juded   72 天前   ❤️ 1

感觉那个统一推送联盟( or 华为推送?)*近覆盖扩展还挺快的,*直接的体现是各大 app 不打开也能收到广告推送了=。=
reed2020
    42

reed2020   72 天前

一个能打的都没有
ptmicky
    43

ptmicky   72 天前

华为推送不是蛮吊的,我之前发的帖子里讲到了,开启了推送,把淘宝卸载了,还给我推送淘宝物流信息,太棒了。
就是淘宝活动广告有点烦人。
AndyAO
    44

AndyAO   72 天前

目前用 MIUI 感觉还挺不错的,因为通知是可以分类设置的,有部分应用很良心,一些重要的通知和广告是分开的,所以直接可以把某些应用的只留下重要的通知.

它还有一些应用,虽然有分开,但名字上根本看不出是什么来,或者说直接没有分开,那么这种情况*好还是设置关键词进行过滤什么的,但 MIUI 还没有这个功能,短信已经有了通知,却没有希望能够尽快的改进.

在之前刷过 xposed,因为 xposed 稳定性也不好,经常会出问题,自己在这方面又完全不懂,也不想折腾了

byte10
    45

byte10   72 天前

@icemaple 哈哈,你这评论到位,现实中还是存在很多这样的人,普通人还是大多数的,他们只会看视频,不会动脑子,从小就是那种自以为是的人。这些人不愿意去思考问题,很多思想都很主观。哎,我很难过,教育还是很重要。现在的教育还是没教会别人怎么去思考问题。
@CodeCodeStudy 你要加油,努力学习知识,谦虚的去了解。
ciaoly
    46

ciaoly   72 天前 via Android

个人比较认可 hms (虽然用的是小米手机)。
目前知道 QQ 邮箱是接入了 hms 的,telegram (银河版)和微信据传也已接入 hms,楼上也说了 QQ 和 Tim 也接入 hms,这样看来几乎所有的 IM (什么 WhatsApp 、Facebook messager 就先不算了)都已接入 hms 了,所以 hms 还是比较好的(非 IM 也没那么高的推送需求不是)
xzg1993
    47

xzg1993   72 天前   ❤️ 1

华为推送还可以啊,我起码我就没遇见过微信收不到推送的情况。
耗电什么的,由于现在大电池和快充,也没有什么感知。
常驻后台,这个也不影响我正常使用,毕竟内存都这么大了。。。
反而苹果的微信推送,我就很不习惯,明明推送到了。打开微信的时候,还有 loading 一会儿才能看到短信。在地铁的时候,loading 半天,整的我特别焦虑
所以一堆人说 Android 推送不如苹果的,是真的使用过嘛?
AlexPUBLIC
    48

AlexPUBLIC   72 天前

@AndyAO 貌似是工信部牵头的,这玩意利益太复杂了,不知道你是不是还记得三网融合,08 年就提了,现在看看
mxT52CRuqR6o5
    49

mxT52CRuqR6o5   72 天前

安卓厂商任你开发推送服务,我微信就是不接入,你能怎么着
确实会比没有推送服务的体验好一丢丢,相比苹果推送还是差很多的
MaverickLee
    50

MaverickLee   72 天前

@xzg1993 #47 确实,点开 Loading 一会这点确实难受,特别是微信(群)消息一多或者信号不好时,简直爆炸
mxT52CRuqR6o5
    51

mxT52CRuqR6o5   72 天前

@xzg1993 安卓版微信不接入任何一家的推送服务的
niceshell
    52

niceshell   72 天前

赞成 36 楼观点,推送看着贼烦
takemeaway
    53

takemeaway   72 天前

iPhone 用户,从来不用推送的,没体验过这个有啥好的。
miniwade514
    54

miniwade514   72 天前 via iPhone

提示:发表观点之前,说清楚是用户视角还是开发者视角。
togou
    55

togou   72 天前

苹果用户能不用苹果的推送么? 这不是就就是屎也得硬啃?
lj2016
    56

lj2016   72 天前 via iPhone

推送除了苹果国内都是垃圾
psllll
    57

psllll   72 天前

微信不支持 mipush 和 huaweipush 说啥都没用
edinina
    58

edinina   72 天前 via Android

@xzg1993 你说的这个跟推送没关系,可以打开后台刷新,我一直开着没觉得费电
sagaxu
    59

sagaxu   72 天前 via Android

只开了微信的推送,其余全关
Zhepro
    60

Zhepro   72 天前

长期用 miui,前几个月换了 iphone8p 小试了一下 ios 系统,*大的感觉就是骚扰电话全打进来了还没有标记,推送还真没感觉有区别
axbx
    61

axbx   72 天前

开发的 app 接入推送通道安卓只有华为小米
zkhhkz123
    62

zkhhkz123   71 天前

Huawei/iPhone 双持 因为推送原因主要 App 都登录在 iPhone 上

话说留意了一下华为上微博 app 的推送 目前应该是系统级推送跟 app 推送并存(查看通知中微博的小 logo 可以看到 有两种推送消息) 并没有完全切换抛弃 app 自己的推送

mcluyu
    63

mcluyu   71 天前

小知识:上面很多人误以为 iOS 的推送跟通知是一个东西,其实是两个,推送你是关不掉的,你能关的只有通知,你看不到通知了不代表 APP 不会给你推送,甚至静默推送唤醒 APP 。
wolfie
    64

wolfie   71 天前

@CodeCodeStudy #36
你弄混了,要不要给指定应用开推送 和 统一推送服务 是两码事。
standin000
    65

standin000   71 天前

小米国外 apptrello,quire 推送不行,国产的丰云行,小牛电动也不行。
dickinpit
    66

dickinpit   71 天前

@learningman #32 在小米上,支持 fcm 也是要开自启动才能及时推送的。telegram 就是,不用*,但必须允许自启。微信一旦允许自启就无限膨胀,不用多久就要占好几个 G 的存储,日常七八百 M 的内存。这都是苹果没有的问题
CodeCodeStudy
    67

CodeCodeStudy   71 天前

@byte10 #45 你倒是说说看,推送的必要性在哪里?
lxiszuhi
    68

lxiszuhi   71 天前

所有消息都经过第三方的服务器再给你,这有什么好的?就为了省那么点电?这时候就不怕私隐问题了?
jiaslbang
    69

jiaslbang   71 天前

评论里的无知无畏:你们讨论这些没啥意义,反正我用不着
byte10
    70

byte10   71 天前

@CodeCodeStudy 有了推送,APP 就不需要后台运行了,省电了,可以跟苹果媲美了。,现在微信你之所以还能收到信息,只不过是手机厂商给微信活路,留它后台。少年要努力啊,提高自己的认知能力,不然以后会很惨的。
Lxcm
    71

Lxcm   70 天前

除了那几个即时通讯类的,其他没什么通知需求。想用就用~
456789
    72

456789   70 天前

群殴的话 苹果不行吧,毕竟人少
WebKit
    73

WebKit   68 天前

@ciaoly #46 华为推送虽然可以 但是支持的 app 没有小米的多。

我查看了我手机上的 APP,只要有推送功能的基本都是支持小米 +华为 或者小米 + OV 或者只有小米的。

其中原因大概跟小米做系统推送做的比较早有关。

可以通过 LibChecker 这个 app 查看 app 支持的推送组件。

iOS架构师_观察者模式

定义:
观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式),一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

%title插图%num

%title插图%num

示例代码:自己实现观察者模式

创建Protocol类型的接口文件SubProtocol协议类

SubProtocol.h

1 #import <Foundation/Foundation.h>
2
3 @protocol SubProtocol <NSObject>
4
5 //用户的信息和从某一个刊物接收的信息
6 – (void)subMessage:(id)message withSubNumber:(NSString *)withSubNumber;
7 @end

创建观察中心SubCenter类
SubCenter.h

1 #import <Foundation/Foundation.h>
2 #import “SubProtocol.h”
3
4 @interface SubCenter : NSObject
5 // 创建书刊订阅号
6 + (void)creatNumber:(NSString *)subNumber;
7
8 // 移除订阅号
9 + (void)removeNumber:(NSString *)subNumber;
10
11 // 添加用户
12 + (void)addUser:(id <SubProtocol>)user wihtNumber:(NSString *)userNumber;
13
14 // 移除用户
15 + (void)removeUser:(id <SubProtocol>)user withNumber:(NSString *)userNumber;
16
17 // 发送消息
18 + (void)sendMessage:(id)message withSubNumber:(NSString *)SubNumber;
19
20 @end

SubCenter.m

1 //
2 //  SubCenter.m
3 //  观察者模式
4 //
5 //  Created by James on 2017/12/9.
6 //  Copyright © 2017年 TZ. All rights reserved.
7
8
9 #import “SubCenter.h”
10
11
12 static NSMutableDictionary *bookCenter = nil;
13 @implementation SubCenter
14
15 //单例
16 + (void)initialize {
17     if (self == [SubCenter class]) {
18         bookCenter = [NSMutableDictionary dictionary];
19     }
20 }
21
22 // 创建书刊订阅号
23 + (void)creatNumber:(NSString *)subNumber {
24     //  NSHashTable 就是一个集合,但是它是弱引用的.
25     NSHashTable *hashTable = [self existNumber:subNumber];
26     if (hashTable == nil) {
27         hashTable = [NSHashTable weakObjectsHashTable];
28         [bookCenter setObject:hashTable forKey:subNumber];
29     }
30 }
31
32 // 移除订阅号
33 + (void)removeNumber:(NSString *)subNumber {
34     NSHashTable *hashTable = [self existNumber:subNumber];
35     if (hashTable) {
36         [bookCenter removeObjectForKey:subNumber];
37     }
38 }
39
40 // 添加用户
41 + (void)addUser:(id <SubProtocol>)user wihtNumber:(NSString *)userNumber {
42     NSHashTable *hashTable = [self existNumber:userNumber];
43     [hashTable addObject:user];
44 }
45
46 // 移除用户
47 + (void)removeUser:(id <SubProtocol>)user withNumber:(NSString *)userNumber {
48     NSHashTable *hashTable = [self existNumber:userNumber];
49     [hashTable removeObject:user];
50 }
51
52 // 发送消息
53 + (void)sendMessage:(id)message withSubNumber:(NSString *)SubNumber {
54     NSHashTable *hashTable = [self existNumber:SubNumber];
55     if (hashTable) {
56         //构造器
57         NSEnumerator *enumerato = [hashTable objectEnumerator];
58         id <SubProtocol> object = nil;
59
60         while (object = [enumerato nextObject]) {
61             if ([object respondsToSelector:@selector(subMessage:withSubNumber:)]) {
62                 [object subMessage:message withSubNumber:SubNumber];
63             }
64         }
65
66     }
67 }
68
69 #pragma mark – 私有方法
70 // 实现了代理方法
71 + (NSHashTable *)existNumber:(NSString *)subStringNumber {
72     return [bookCenter objectForKey:subStringNumber];
73 }
74
75 @end

ViewController调用

1 #import “ViewController.h”
2 #import “SubCenter.h”
3
4
5 static NSString *SCIENCE = @”SCIENCE”;
6 @interface ViewController () <SubProtocol>
7
8 @end
9
10 @implementation ViewController
11
12 – (void)viewDidLoad {
13     [super viewDidLoad];
14     // Do any additional setup after loading the view, typically from a nib.
15     // 创建订阅
16     [SubCenter creatNumber:SCIENCE];
17
18     // 添加订阅
19     [SubCenter addUser:self wihtNumber:SCIENCE];
20
21     // 发送消息
22     [SubCenter sendMessage:@”11″ withSubNumber:SCIENCE];
23 }
24
25 – (void)subMessage:(id)message withSubNumber:(NSString *)withSubNumber {
26     NSLog(@”—-%@—-%@”,message, withSubNumber);
27 }
28
29
30 @end

iOS架构师_策略模式

什么是策略设计模式?
概念:定义一系列的算法,并且将每个算法封装起来,算法之间还可以互相替换。这种设计模式称为策略模式。

为了解决if-else和switch-case的问题,在实际开发中,较长的if-else会使代码阅读困难。

%title插图%num

代码示例:下面是一个简单的if-else代码

Demo1

1 #import “ViewController.h”
2 typedef NS_ENUM(NSInteger) {
3     Count01,
4     Count02,
5     Count03,
6     Count04,
7     Count05,
8 }EnumCount;
9
10 @interface ViewController ()
11
12 @end
13
14 @implementation ViewController
15
16 – (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
17     EnumCount count = Count04;//声明枚举,并给了一个固定的输入值
18     if (count == 1) {
19         NSLog(@”count = %lu”,count);
20
21     } else if (count == 2) {
22         NSLog(@”count = %lu”,count);
23
24     }else if (count == 3) {
25         NSLog(@”count = %lu”,count);
26
27     }else if (count == 4) {
28         NSLog(@”count = %lu”,count);
29
30     } else {
31         NSLog(@”count = %lu”,count);
32     }
33 }
34 @end

我们使用正常的代码抽离方式对其优化分离。

创建一个NSObject的类,Logic

Logic.h

1 #import <Foundation/Foundation.h>
2
3 typedef NS_ENUM(NSInteger) {
4     Count01,
5     Count02,
6     Count03,
7     Count04,
8     Count05,
9 }EnumCount;
10
11 @interface Logic : NSObject
12
13 + (NSUInteger)logic:(NSUInteger)integer;
14
15 @end

Logic.m

1 #import “Logic.h”
2
3 @implementation Logic
4 + (NSUInteger)logic:(NSUInteger)integer {
5     NSUInteger num;
6     if (integer == 1) {
7         num = 1;
8
9     } else if (integer == 2) {
10         num = 2;
11
12     }else if (integer == 3) {
13         num = 3;
14
15     }else if (integer == 4) {
16         num = 4;
17
18     } else {
19         num = 0;
20     }
21     return num;
22 }
23 @end

那么修改ViewController如下

1 #import “ViewController.h”
2 #import “Logic.h”
3
4 @interface ViewController ()
5
6 @end
7
8 @implementation ViewController
9
10 – (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
11     EnumCount count = Count04;
12     NSUInteger integer = [Logic logic:count];
13     NSLog(@”integer = %lu”, integer);
14 }
15 @end

那么如何使用策略模式呢?

新建继承自NSObject 的 BaseType类

BaseType.h文件

1 #import <Foundation/Foundation.h>
2
3 typedef NS_ENUM(NSInteger) {
4     Count01,
5     Count02,
6     Count03,
7     Count04,
8     Count05,
9 }EnumCount;
10
11 @interface BaseType : NSObject
12 //返回计数结果
13 +(NSUInteger)backCountResult;
14 @end

BaseType.m

1 #import “BaseType.h”
2
3 @implementation BaseType
4 //抽象方法
5 +(NSUInteger)backCountResult {
6     //编写代码
7     return nil;
8 }
9 @end

创建继承自BaseType的子类CountTypes01

CountTypes01.h

1 #import “BaseType.h”
2
3 @interface CountTypes01 : BaseType
4
5 @end

CountTypes01.m

1 #import “CountTypes01.h”
2
3 @implementation CountTypes01
4
5 + (NSUInteger)backCountResult {
6     // 编写代码
7     return 10;
8 }
9 @end

那么修改ViewController如下

1 #import “ViewController.h”
2 #import “CountTypes01.h”
3
4 @interface ViewController ()
5
6 @end
7
8 @implementation ViewController
9
10 – (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
11     NSUInteger integer = [CountTypes01 backCountResult];
12
13     NSLog(@”integer = %lu”, integer);
14
15 }
16 @end

优缺点
策略模式的优点是能解决代码的耦合度,但是它是有牺牲的,为了解决代码耦合度,我们需要创建更多的类。

%title插图%num

Demo2
需求:验证两个textField的输入条件

%title插图%num

初始代码:
ViewController.m

1 #import “ViewController.h”
2
3 @interface ViewController () <UITextFieldDelegate>
4 @property (weak, nonatomic) IBOutlet UITextField *letterInput; /**< 字母输入 */
5 @property (weak, nonatomic) IBOutlet UITextField *numberInput; /**< 数字输入 */
6 @end
7
8 @implementation ViewController
9
10 – (void)viewDidLoad {
11     [super viewDidLoad];
12     // Do any additional setup after loading the view, typically from a nib.
13     self.letterInput.delegate = self;
14     self.numberInput.delegate = self;
15 }
16
17 – (IBAction)btnClick:(id)sender {
18     [self.view endEditing:YES];
19 }
20
21 #pragma mark – UITextFieldDelegate
22 – (void)textFieldDidEndEditing:(UITextField *)textField {
23     if (textField == self.letterInput) {
24         // 验证它的输入值, 确保它输入的是字母
25         NSString *outputLatter = [self validateLatterInput:textField];
26         if (outputLatter) {
27             NSLog(@”—%@”,outputLatter);
28         }else {
29             NSLog(@”—输入是空的”);
30         }
31
32     } else if (textField == self.numberInput) {
33        // 验证它的输入值, 确保它输入的是数字
34         NSString *outputNumber = [self validateNumberInput:textField];
35         if (outputNumber) {
36             NSLog(@”—%@”,outputNumber);
37         }else {
38             NSLog(@”—输入是空的”);
39         }
40     }
41 }
42
43 #pragma mark – 验证输入
44 – (NSString *)validateLatterInput:(UITextField *)textField {
45     if (textField.text.length == 0) {
46         return nil;
47     }
48
49     // ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
50     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@”^[a-zA-Z]*$” options:NSRegularExpressionAnchorsMatchLines error:nil];
51     //NSMatchingAnchored 从开始处就进行*限匹配
52     NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
53
54     NSString *outLatter = nil;
55     // 进行判断,匹配不符合表示0的话, 就走下面的逻辑
56     if (numberOfMatches == 0) {
57         outLatter = @”不全是字母, 输入有误,请重新输入”;
58     } else {
59         outLatter = @”输入正确,全部是字母”;
60     }
61
62     return outLatter;
63 }
64
65 – (NSString *)validateNumberInput:(UITextField *)textField {
66     if (textField.text.length == 0) {
67         return nil;
68     }
69
70     // ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
71     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@”^[0-9]*$” options:NSRegularExpressionAnchorsMatchLines error:nil];
72
73     NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
74
75     NSString *outLatter = nil;
76     // 进行判断,匹配不符合表示0的话, 就走下面的逻辑
77     if (numberOfMatches == 0) {
78         outLatter = @”不全是数字, 输入有误,请重新输入”;
79     } else {
80         outLatter = @”输入正确,全部是数字”;
81     }
82
83     return outLatter;
84
85 }
86
87
88 @end

我们知道,所有的设计模式都是为了代码解耦合所使用的,代价肯定是需要创建其他的类,将代码分离。

那么我们如何使用策略模式来优化代码呢?

首先我们创建一个继承自NSObject的抽象类:InputTextFieldValidate

InputTextFieldValidate.h

1 #import “InputTextFieldValidate.h”
2
3 @implementation InputTextFieldValidate
4 – (BOOL)validateInputTextField:(UITextField *)textField {
5     return NO;
6 }
7 @end

InputTextFieldValidate.m

1 #import “LatterTextFieldValidate.h”
2
3 @implementation LatterTextFieldValidate
4
5 – (BOOL)validateInputTextField:(UITextField *)textField {
6     if (textField.text.length == 0) {
7         self.attributeInputStr = @”字母不能是空的”;
8         return nil;
9     }
10
11     // ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
12     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@”^[a-zA-Z]*$” options:NSRegularExpressionAnchorsMatchLines error:nil];
13
14     NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
15
16 //    NSString *outLatter = nil;
17     // 进行判断,匹配不符合表示0的话, 就走下面的逻辑
18     if (numberOfMatches == 0) {
19         self.attributeInputStr = @”不全是字母, 输入有误,请重新输入”;
20     } else {
21         self.attributeInputStr = @”输入正取,全部是字母”;
22     }
23
24     return self.attributeInputStr == nil ? YES : NO;
25 }
26 @end

 

然后创建一个继承自UITextField的类:CustomTextField(自定义的TextField)

CustomTextField.h

1 #import <UIKit/UIKit.h>
2 #import “InputTextFieldValidate.h”
3
4 @interface CustomTextField : UITextField
5
6 // 抽象的策略
7 @property (nonatomic, strong) InputTextFieldValidate *inputValidate;
8
9 // 验证是否符合要求
10 – (BOOL)validate;
11 @end

CustomTextField.m

1 #import <UIKit/UIKit.h>
2 #import “InputTextFieldValidate.h”
3
4 @interface CustomTextField : UITextField
5
6 // 抽象的策略
7 @property (nonatomic, strong) InputTextFieldValidate *inputValidate;
8
9 // 验证是否符合要求
10 – (BOOL)validate;
11 @end

ViewController.m就简洁多了,修改如下:

1 #import <UIKit/UIKit.h>
2 #import “InputTextFieldValidate.h”
3
4 @interface CustomTextField : UITextField
5
6 // 抽象的策略
7 @property (nonatomic, strong) InputTextFieldValidate *inputValidate;
8
9 // 验证是否符合要求
10 – (BOOL)validate;
11 @end

ViewController.m就简洁多了,修改如下:

1 #import “ViewController.h”
2 #import “CustomTextField.h”
3 #import “LatterTextFieldValidate.h”
4 #import “NumberTextFieldValidate.h”
5
6
7 @interface ViewController () <UITextFieldDelegate>
8 @property (weak, nonatomic) IBOutlet CustomTextField *letterInput; /**< 字母输入 */
9 @property (weak, nonatomic) IBOutlet CustomTextField *numberInput; /**< 数字输入 */
10 @end
11
12 @implementation ViewController
13
14 – (void)viewDidLoad {
15     [super viewDidLoad];
16     // Do any additional setup after loading the view, typically from a nib.
17     self.letterInput.delegate = self;
18     self.numberInput.delegate = self;
19
20     // 初始化
21     self.letterInput.inputValidate = [LatterTextFieldValidate new];
22     self.numberInput.inputValidate = [NumberTextFieldValidate new];
23
24 }
25
26 – (IBAction)btnClick:(id)sender {
27     [self.view endEditing:YES];
28 }
29
30 #pragma mark – UITextFieldDelegate
31 – (void)textFieldDidEndEditing:(UITextField *)textField {
32     if ([textField isKindOfClass:[CustomTextField class]]) {
33         [(CustomTextField *)textField validate];
34     }
35 }
36
37 @end

优点:控制器代码简洁,分离代码复用性高,逻辑清晰,方便拓展。

Conda环境离线迁移

Conda环境离线迁移

1. 背景
笔者所在公司*近要在局域网内部署NLP算法模型,由于需求方对数据安全有严格要求,新服务器所在局域网不能直接访问Internet,因此需要将模型所需的运行环境离线迁移到新服务器中。

2. 方案
2.1 conda-pack
conda-pack是一个命令行工具,用于打包conda环境。该命令会将坏境中安装的软件包的二进制文件进行打包。
注:本方法不需要下载安装包,因此,conda-pack需要指定平台和操作系统,目标计算机必须于源计算机有相同的平台和操作系统。

2.1.1 打包
在conda的base环境中安装conda-pack;
pip install conda-pack
1
打包一个环境
# Pack environment my_env into my_env.tar.gz
conda pack -n my_env

# Pack environment my_env into out_name.tar.gz
conda pack -n my_env -o out_name.tar.gz

# Pack environment located at an explicit path into my_env.tar.gz
conda pack -p /explicit/path/to/my_env

2.1.2 重现
# Unpack environment into directory `my_env`
mkdir -p my_env
tar -xzf my_env.tar.gz -C my_env

# Use Python without activating or fixing the prefixes. Most Python
# libraries will work fine, but things that require prefix cleanups
# will fail.
./my_env/bin/python

# Activate the environment. This adds `my_env/bin` to your path
source my_env/bin/activate

# Run Python from in the environment
(my_env) $ python

# Cleanup prefixes from in the active environment.
# Note that this command can also be run without activating the environment
# as long as some version of Python is already installed on the machine.
(my_env) $ conda-unpack

2.2 pip download
利用pip将服务运行所依赖的包下载到本地,拷贝到目标服务器进行离线安装。

保存虚拟环境到requirements.txt
pip list –format=freeze > requirements.txt

备注: 此处不使用pip freeze命令是因为pip freeze导出的文件会出现@ file://的问题,导致后续下载依赖包的时候出现问题。

下载依赖包到指定目录
pip download -r requirements.txt -d “/home/admin/packs” -i https://pypi.tuna.tsinghua.edu.cn/simple

将requirements.txt和依赖包拷贝到目标服务器
在目标服务器创建conda虚拟环境
conda create -n my_env python=3.6.5 pip=10.0.1 –offline

备注:

–offline:指定离线创建虚拟环境;
python=3.6.5 & pip=10.0.1:指定默认的python版本号、并安装pip工具,如果不安装pip,则改虚拟环境使用默认的pip工具,就无法将依赖包安装到新虚拟环境。Anaconda自带的package在anaconda3/pkgs目录下,可自行查看;
切换到虚拟环境,并安装依赖包
pip install -U –no-index –find-links=./packs -r requirements.txt

备注: 若出现Cannot uninstall ‘xxxx’. It is a distutils installed project and thus we cannot accurately det…(xxx是某package的名称),使用如下命令进行解决:

pip install -U –ignore-installed –no-index –find-links=./packs xxx

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速