7大原则
- 单一职责原则(Single Responsibility Principle SRP)
如何划分一个类、一个函数的职责,每个人都有自己的看法,这需要根据个人经验、 具体的业务逻辑而定。但是,它也有一些基本的指导原则,例如,两个完全不一样的功能就不应该放在一个类中。一个类中应该是一组相关性很高的函数、数据的封装。工程师可以不断地审视自己的代码,根据具体的业务、功能对类进行相应的拆分,这是程序员优化代码迈出的第一步。 - 开闭原则(Open Closed Principle OCP)
软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。 - 里氏替换原则(Liskov Substitution Principle LSP)
所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。
里氏替换原则的关键就是建立抽象,通过抽象建立规范,具体的实现在运行时替换掉抽象,保证系统的扩展性、灵活性。开闭原则和里氏替换原则往往是生死相依、不弃不离的,通过里氏替换来达到对扩展开放,对修改关闭的效果。然而,这两个原则都同时强调了一个OOP的重要特性抽象,因此,在开发过程中运用抽象是走向代码优化的重要一步。
比如ViewGroup中的addView(View view),这个view可以是View的各种子类,也可以是自定义View。 - 依赖倒置原则(Dependence Inversion Principle DIP)
模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。 - 接口隔离原则(Interface Segregation Principle ISP)
客户端不应该依赖它不需要的接口。另一种定义是:类间的依赖关系应该建立在最小的接口上。 - 迪米特原则(Law of Demeter LOD),又叫最少知识原则(Least Knowledge Principle LKP)
一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,类的内部如何实现与调用者或者依赖者没关系,调用者或者依赖者只需要知道它需要的方法即可,其他的可一概不用管。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。 - 组合/聚合复用原则(Composition/Aggregation Principle CARP)
在面向对象的设计中,如果直接继承基类,会破坏封装,因为继承将基类的实现细节暴露给子类;如果基类的实现发生改变,则子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性。于是就提出了组合/聚合复用原则,也就是在实际开发设计中,尽量使用合成/聚合,不要使用类继承。即在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分,新对象通过向这些对象的委派达到复用已有功能的目的。就是说要尽量的使用合成和聚合,而不是继承关系达到复用的目的。
23中设计模式
- 单例模式
①静态常量(静态常量或者静态代码块)
②双重检查同步代码块
③静态内部类
④枚举
⑤AtomicRerence - Builder模式
通常作为配置类的构建器将配置的构建和表示分离开来,同时也是将配置从目标类中隔离出来, 避免过多的setter方法。Builder模式比较常见的实现形式是通过调用链实现, 这样使得代码更简介、 易懂。
public class Config {
int config1;
int config2;
private Config () {
}
public static class Buider {
int config1;
int config2;
public Buider setConfig1(int config1){
this.config1 = config1;
return this;
}
public Buider setConfig2(int config2){
this.config2 = config2;
return this;
}
private void apply(Config config){
config.config1 = this.config1;
config.config2 = this.config2;
}
public Config create(){
Config config = new config();
this.apply(config);
return config;
}
}
复制代码
-
原型模式
原型模式本质上就是对象拷贝,容易出现的问题是深拷贝、浅拷贝。使用原型模式可以解决构建复杂对象的资源消耗问题,能够在某些场景下提升创建对象的效率。 还有一 个重要的用途就是保护性拷贝,也就是某个对象对外可能是只读的,为了防止外部对这个只读对象修改, 通常可以通过返回一个对象拷贝的形式实现只读的限制。 -
工厂方法模式
-
抽象工厂模式
在任何需要生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂模式,用 new就可以完成创建的对象无需使用工厂模式。方便创建同种产品类型的复杂参数对象。 -
策略模式
如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或者策略有不同的实现 类,这样在程序客户端就可以通过注入不同的实现对象来实现算法或者策略的动态替换,这种模式 的可扩展性、可维护性也就更高。策略模式主要用来分离算法,在相同的行为抽象下有不同的具体实现策略。这个模式很好地演示了开闭原则,也就是定义抽象,注入不同的实现,从而达到很好的可扩展性。 -
状态模式
状态模式中的行为是由状态来决定的,不同的状态下有不同的行为。状态模式和策略模式的结 构几乎完全一样,但它们的目的、本质却完全不一样。状态模式的行为是平行的、不可替换的, 策略模式的行为是彼此独立、可相互替换的。用一句话来表述,状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。 -
责任链模式
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。 -
解释器模式
给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。 -
命令行模式
将调用者与行为实现者解耦 -
观察者模式
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖千它的对象都会得到通知并被自动更新。 -
备忘录模式
在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样,以后就可以将该对象恢复到原先保存的状态。 -
迭代器模式
提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示。 -
模板方法模式
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 使用场景:
(1)多个子类有公有的方法, 并且逻辑基本相同时。
(2)重要、复杂的算法,可以把核心算法设计为模板方法周一边的相关细节功能则由各个子类实现。
(3)重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩 子函数约束其行为。 -
访问者模式
定义及使用场景
定义:
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
可以对定义这么理解:有这么一个操作,它是作用于一些元素之上的,而这些元素属于某一个对象结构。同时这个操作是在不改变各元素类的前提下,在这个前提下定义新操作是访问者模式精髓中的精髓。
使用场景:
(1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
(2)需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。 -
中介者模式
定义:中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使它们可以松散耦合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。
使用场景: 当对象之间的交互操作很多且每个对象的行为操作都依赖彼此时,为防止在修改一个对象的行为时,同时涉及很多其他对象的行为,可使用中介者模式。
- 代理模式
静态代理,动态代理。 - 组合模式
View和ViewGroup,Folder和File - 适配器模式
类适配器、对象适配器。Recyclerview的adapter是将数据转成items。 - 装饰者模式
动态地给一个对象添加一些额外的职责。 与代理模式的区别:
- 装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期增加行为。
- 代理模式,控制对象的访问。
- 享元模式
比如连接池、线程池等各种缓存池,复用减少内存、创建开销和gc。 - 外观模式
向外提供SDK时的封装。子模块的封装。向外提供一个统一高层次的接口,屏蔽实现细节。 - 桥接模式
将抽象部分与实现部分分离,使它们都可以独立地进行变化。桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。