今年的Google IO 大会上,Google宣布Kotlin成为Android的官方语言,有兴趣的可以去学习下,Java作为android的第一个语言,还是需要把打这部分知识打牢固的。(这部分内容只是当作自己的复习)
1、三大特性
Java做为面向对象的语言,他的三大特性:继承
、封装
、多态
。
2、6大原则
单一职责原则(Single Responsibility Principle)
定义: 不要存在多于一个导致类变更的原因。也就是说,一个类只负责一项职责
案例:工厂A负责生产面包和牛奶,当生产面包的需求发生变化时,需要改变工厂生产模式,这事就有可能影响牛奶的生产。
解决方案:遵循单一职责原则,分别建立两个子公司,一个负责生产面包,一个负责生产牛奶,这样如果面包需求变了就不会影响牛奶的生产了。
如果有想学习java的程序员,可来我们的java学习扣qun:79979,2590免费送java的视频教程噢!小编是一名5年java开发经验的全栈工程师,整理了一份适合18年学习的java干货,送给每一位想学的小伙伴,欢迎大家一起学习哦。
public class Factory {
public Factory () {
super();
}
public void product() {
System.out.println(“生产饼干”);
System.out.println(“生产葡萄干”);
}
}
public class Main {
public static void main (String [] args) {
new Factory.product();
}
}
遵循单一职责原则,做如下修改:
public class FactoryA {
public void product() {
System.out.println(“生产饼干”);
}
}
public class FactoryB {
public void product() {
System.out.println(“生产葡萄干”);
}
}
public class Factory {
private FactoryA mA;
private FactoryB mB;
public Factory () {
super();
mA = new FactoryA();
mB = new FactoryB();
}
public void product() {
mA.product();
mB.product();
}
}
我理解的单一职责原则就是在开发过程中尽量将一些类的职责明确、唯一。
遵循单一职责的优点:
- 降低复杂度
- 提高可读性
- 降低对其他功能的影响
可是可能由于职责的颗粒化,我们往往会违背这个原则,这个原因为职责扩散(就是因为某些原因,我们要吧职责之一再次细分)
关于这部分请看 单一职责原则(1)
里氏替换原则 (Liskov Substitutiion Principle)
定义:所有引用基类的地方必须能够透明地使用其子类的对象
通俗的说,就是用父类的地方可以用子类去代替,但是用子类的地方用父类不一定能代替。
里氏替换原则包含4层含义:
- 子类必须完全实现父类的方法
- 子类可以有自己的方法
- 当子类的方法重载父类的方法时,形参要比父类的范围更大
- 当子类的方法实现父类的抽象方法时,方法的返回值要比父类更严格
例子:
public class Test {
public static void main(String [] args) {
Man m = new Man();
}
}
abstract class Cat {
public void eat(){}
}
/**
* 人可以喂猫吃东西,可以有不同种类的猫
*/
class Man {
private Cat mCat;
public void setCat(Cat mCat) {
this.mCat = mCat;
}
public void feed() {
mCat.eat();
System.out.println("正在进食...");
}
}
class Garfield extends Cat {
@Override
public void eat() {
System.out.println("加菲猫进食...");
}
}
class Folds extends Cat {
@Override
public void eat() {
System.out.println("折耳猫进食...");
}
}
优点: 可以对后期版本升级,增添子类时都可以很好的维护
依赖倒置原则(Dependence Inversion Principle)
定义: 高层模块不应该依赖底层模块,应该依赖其抽象,抽象不应该依赖其细节,细节应该依赖其抽象。
底层模块:负责基本的操作
高层模块:由多个底层模块组成,负责复杂的操作
抽象:在Java中指的是接口或者抽象类
依赖倒置的核心思想是面向接口编程,相对于细节的多变性,抽象的稳定性更高一些。以抽象为基础搭建起来的架构比以细节搭建起来的框架稳定的多。下面我们用例子来解释下依赖倒置原则。
class Bread {
public String getContent () {
return "面包生产出来了"
}
}
class Factory {
public void poduct(Bread bread) {
System.out.println("工厂开始生产");
System.out.println(book.getContent());
}
}
public class Test {
public static void main(String [] args) {
Factory mFactory = new Factory();
mFactory.poduct(new Bread());
}
}
假如现在需求变了,不再生产面包,改为生产牛奶,这个时候工厂是做不了的,它只能生产面包。这样的话耦合性就会很高了。
遵循以来倒置的原则,我们做如下修改:
interface Model {
public String getContent();
}
class NewBread implements Model {
public String getContent() {
return "面包生产出来了"
}
}
class Milk implements Model {
public String getContent() {
return "牛奶生产出来了"
}
}
class Factory {
public void product(Model model) {
System.out.println("工厂开始生产")
System.out.println(model.getContent());
}
}
public class Test {
public static void main(String [] args) {
Factory mFactory = new Factory();
mFactory.product(new NewBread());
mFactory.product(new Milk())
}
}
依赖有三种写法
1、构造函数传递依赖
class Factory {
private Model model
public Factory(Model model) {
this.model = model;
}
public void product () {
System.out.println("工厂开始生产")
System.out.println(model.getContent());
}
}
2、setter方法传递
class Factory {
private Model model
public void setModel(Model model) {
this.model = model;
}
public void product () {
System.out.println("工厂开始生产")
System.out.println(model.getContent());
}
}
3、接口传递依赖
如 最开始给的例子
接口隔离原则 (Interface segregation Principle)
定义:客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。
我们用一个例子来说明下:
interface I {
public void m1();
public void m2();
public void m3();
public void m4();
}
class B implements I {
public void m1() {
System.out.println("类B实现接口I的方法1");
}
public void m2() {
System.out.println("类B实现接口I的方法2");
}
public void m3(){}
public void m4(){}
}
class A {
public void depend1(I i) {
i.m1();
}
public void depend2(I i) {
i.m2();
}
}
class C {
public void depend1(I i) {
i.m3();
}
public void depend2(I i) {
i.m4();
}
}
class D implements I {
public void m1() {
}
public void m2() {
}
public void m3(){
System.out.println("类D实现接口I的方法3");
}
public void m4(){
System.out.println("类D实现接口I的方法4");
}
}
public class Client {
public static void main(String [] args) {
A a = new A();
a.depend1(new B());
a.depend2(new B());
C c = new C();
c.depend1(new D());
c.depend2(new D());
}
}
可以看到,对了类B来说 方法3和方法4是不需要的,但是由于接口I中有这两个方法,所以必须实现它。同理,对于类D来说,方法1和方法2是不需要的。这样的话就不符合接口隔离原则,下面我们修改一下以符合其原则:
interface I {
public void m1();
public void m2();
}
interface I1 {
public void m3();
public void m4();
}
class B implements I {
public void m1() {
System.out.println("类B实现接口I的方法1");
}
public void m2() {
System.out.println("类B实现接口I的方法2");
}
}
class A {
public void depend1(I i) {
i.m1();
}
public void depend2(I i) {
i.m2();
}
}
class C {
public void depend1(I1 i) {
i.m3();
}
public void depend2(I1 i) {
i.m4();
}
}
class D implements I1 {
public void m3(){
System.out.println("类D实现接口I的方法3");
}
public void m4(){
System.out.println("类D实现接口I的方法4");
}
}
我理解的接口隔离原则是:建立单一的接口,尽量接口细化,不要建立臃肿的接口,接口中的方法尽量少。
接口隔离原则是对接口进行的规范约束,应该要主要一下几点(摘自《设计模式之禅》)
- 接口尽量小
接口在遵循单一职责原则的情况下,尽量减少和接口中方法,不不是无休止的细化接口。
- 高内聚
高内聚是提高接口、类、模块的处理能力,减少对外的交互。在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对外越有利,变更的风险也就越少,同时有利于降低成本
- 定制服务
根据需求分析,必要时为特殊用户提供定制的接口,尽量避免不同操作人群使用同一接口,这样会降低系统的享用速度和扩展性。
- 接口设计是有限度的
根据开发情景划分设计接口,在开发过程中接口设计的颗粒度越小,系统灵活性越高。并不是以为的将接口细化。
迪米特法则(Low of Demeter,LoD)
定义
:一个对象应该对其他对象有最少的了解,只与直接的朋友通信。
朋友关系
:每个对象都必然会与其他对象有耦合关系,两个对象之间的耦合关系就称为朋友关系。
迪米特法则定义的是类之间的关系要低耦合,一个类中的朋友不要太多,这样后期维护起来比较方便。
举个例子:老师清点人数,老师通过班长清点人数。
public class Teacher {
public void command (ClassMonitor classMonitor) {
List<Student> list = new ArrayList<Student>();
for(int i=0;i<20;i++) {
list.add(new Student());
}
classMonitor.count(list)
}
}
class ClassMonitor {
public void count(List<Student> list) {
System.out.println("班长说:全班的人数是。。。"+list.size());
}
}
class Student {
}
public class Test {
public static void main(String [] args) {
new Teacher().command(new ClassMonitor());
}
}
在Teacher类中,一个方法调用的两个类的实例,分别是ClassMonitor和Student类。对于Teacher类来说,朋友类只有ClassMonitor,迪米特法则告诉我们只与朋友类通信,所以这种设计就违反了迪米特法则。
在Java中朋友的定义为:出现在成员变量。方法的输入输出类称为朋友类,在方法体内的类不属于朋友类
我们改进一下,以复合迪米特法则
public class Teacher {
public void command (ClassMonitor classMonitor) {
classMonitor.count();
}
}
class ClassMonitor {
List<Student> list;
public ClassMonitor(List<Student> list) {
this.list = list;
}
public void count(List<Student> list) {
System.out.println("班长说:全班的人数是。。。"+list.size());
}
}
class Student {
}
public class Test {
public static void main(String [] args) {
List<Student> list = new ArrayList<Student>();
for(int i=0;i<20;i++) {
list.add(new Student());
}
new Teacher().command(new ClassMonitor(list));
}
}
迪米特法则给类的低耦合提出了四个基本要求
1. 只和朋友类交流
2. 朋友间也是有距离的
在java中的实现思想就是:类A与类B之间有依赖关系,并在方法输入或输出中创建该类的实例,那么他们属于朋友类,但是类A不可以过分操作类B的方法
3. 是自己的就是自己的
如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中
4. 谨慎使用serializable
开闭原则(Open Closed Principle,OCP)
定义:一个软件实体如类、模块和函数应该对扩展开发,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
软件实体包括:
- 项目或软件产品中按照一定的逻辑规则划分的模块
- 抽象和类
- 方法
一个实例
- IMilk 定义了两个属性:厂商和价格
- Supermarket是超市
- NovelMilk是一个具体的实现类
public class Supermarket {
public static List<NovelMilk> list = new ArrayList<NovelMilk>();
static {
list.add(new NovelMilk("伊利", 60))
list.add(new NovelMilk("安慕希",55))
}
public static void main(String [] args) {
for(NovelMilk milk: list) {
System.out.println("牛奶厂商" + milk.getManufacturers()+"\t 价格:"+ milk.getPrice()+ "元")
}
}
}
interface IMilk {
public String getManufacturers();
public int getPrice();
}
class NovelMilk implements IMilk {
private int price;
private String manufacturers;
public NovelMilk(String manufacturers, int price) {
this.manufacturers = manufacturers;
this.price = price;
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return this.price;
}
@Override
public String getManufacturers() {
// TODO Auto-generated method stub
return this.manufacturers;
}
}
需求更改:超市进行打折促销,规定 50元以下的 9折出售。
如果要在NovelMilk中修改的话,修改量就会很大,而且违背了开闭原则,
解决方案:通过扩展实现变化
public class Supermarket {
public static List<NovelMilk> list = new ArrayList<NovelMilk>();
static {
list.add(new OffNovelMilk("伊利", 60))
list.add(new OffNovelMilk("安慕希",55))
}
public static void main(String [] args) {
for(NovelMilk milk: list) {
System.out.println("牛奶厂商" + milk.getManufacturers()+"\t 价格:"+ milk.getPrice()+ "元")
}
}
}
interface IMilk {
public String getManufacturers();
public int getPrice();
}
class NovelMilk implements IMilk {
private int price;
private String manufacturers;
public NovelMilk(String manufacturers, int price) {
this.manufacturers = manufacturers;
this.price = price;
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return this.price;
}
@Override
public String getManufacturers() {
// TODO Auto-generated method stub
return this.manufacturers;
}
}
class OffNovelMilk extends NovelMilk{
public OffNovelMilk(String manufacturers, int price) {
super(manufacturers, price);
// TODO Auto-generated constructor stub
}
@Override
public int getPrice() {
int rePrice = super.getPrice();
int nowPrice = 0;
if(rePrice<50){
nowPrice = rePrice*90/100;
}else{
nowPrice = rePrice;
}
return nowPrice;
}
}