ARTS Week5
Algorithm
此题用到了双指针,从数组两头开始计算。那么此时的宽是数组的长度,高是数组两个下标取最短。与初始化的最大面积比较,取最大。
然后是看左下标的值是否小于右下标,如果小于,那么左指针向右移;否则右指针向左移。因为如果是移动大的一边,小的一边还是不变,那么面积只能是小于等于原来的面积。
Review
SOLID Principles every Developer Should Know
每个开发者都必须知道 SOLID 原则。
SRP: 每个类都应该只有唯一的功能
当我们设计类的时候,应该着眼于将相同功能放在一起,它们会因为相同的原因而改变;否则,我们应该尝试将功能分开。
OCP:软件实体应该是通过扩展来实现变化
当我们需要增加某些功能某些变化的时候,应该是通过扩展的方式来实现的;而不是通过改变现有的代码来实现变化。
LSP:一个子类必然可以替代它的超类
里氏替代原则是继承复用的基石。只有当衍生类可以替代掉基类,并且软件单位的功能不会因此而受到影响时,基类才能被真正复用。
ISP:不强迫客户端依赖它不使用的接口
我们应该将接口按照不同客户端细化,创建专用的接口。而不是创建一个接口,将所有的方法都放进去,并要求所有实现这个接口的客户端都必须实现所有的方法。
DIP:依赖性应该是抽象而不是具体的东西
A. 高层模块不应依赖于低层模块。两者都应该依赖于抽象。
B. 抽象不应依赖于细节。细节应该依赖于抽象。
Tip
Java中的单例模式
饿汉模式
饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在。它的优点是它只会在类加载的时候创建一次;但是缺点同样明显,即使没有用到这个实例也会被创建,浪费了内存。
懒汉模式
懒汉模式中单例是在需要的时候才去创建的。但是在多个线程可能会并发调用它的getInstance()方法,导致创建多个实例。
所以,为了解决线程同步问题,我们需要加锁来解决
双重校验锁
上面加锁的懒汉模式虽然解决了同步的问题,又解决了延迟加载的问题,但是依然存在性能问题。synchronized修饰的同步方法比一般方法要慢很多,如果多次调用getInstance(),累积的性能损耗就比较大了
双重校验锁即实现了延迟加载,又解决了线程并发问题,同时还解决了执行效率问题。然而双重校验锁还是存在着缺陷。
指令重排优化是指在不改变原语义的情况下,通过调整指令的执行顺序让程序运行的更快
由于指令重排优化的存在,导致初始化Singleton和将对象地址赋给instance字段的顺序是不确定的。
所以有一种情况发生:
一个线程创建单例对象,然而没有初始化之前,就为该对象分配了内存空间并为该对象的字段设置默认值;此时如果有另一个进程前来访问,那么调用getInstance,就会因为没有初始化而获取状态不正确的对象,就会报错。
解决方法:
volatile的一个语义是禁止指令重排序优化,也就保证了instance变量被赋值的时候对象已经是初始化过的,从而避免了上面说到的问题。
静态内部类【推荐】
系统启动时内部类是不会加载的。但当内部类第一次被调用时,则会成功初始化实例
可以看到内部类 SingletonHolder 也使用了饿汉模式加载。前面说过饿汉模式的缺点是即使没有用到这个实例也会被创建,浪费了内存。
但是在内部类中,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。
Share
在开发过程中,我们应该尽量避免重复代码或者相同逻辑的出现,因为重复代码会很容易造成修改遗漏。
避免长函数,因为他的可读性非常低。横向过长的代码,可以通过代码格式化、CheckStyle插件来发现和消除。纵向过长的代码,可以通过分解提炼成多个小函数。
过大的类。当一个类过大时,可能是因为这个类负责的职务太过复杂,不符合SRP原则。应该尝试把类分解成多个职责单一的类。
过长的参数列表。首先就是可读性差;其次就是如果需要添加新的参数,会让调用方也发生变化。可以通过传入一个包含多个属性的参数对象
避免无用的注释。比如没有用的逻辑代码,误导性注释,日志式注释等等。
评论