七大原则
1.单一职责:一个类只负责一个功能模块
好处
①降低类的复杂度
②提高可维护性与可读性
③变更方便。
下面三种写法,第一种没有遵守单一原则,加入要修改对应的功能,或者传入的对象不同,那么就要修改整个类的方法。第二种方法遵守了类的单一原则,问题就是每次拓展都需要拓展整个类,代码非常多,最后一种相对来说比较好只是方法遵守单一原则,代码量相对更少。
没有遵守单一原则
public class SingleResponsibility1 {
public static void main(String[] args) {
//没有遵守单一原则
Vehicle vehicle=new Vehicle();
vehicle.run("飞机");
vehicle.run("火车");
}
}
class Vehicle{
public void run(String vehicle){
System.out.println(vehicle+"正在运行。。。");
}
}
类上遵守单一原则
public class SingleResponsibility2 {
public static void main(String[] args) {
//太多代码要写,如果功能更多
RoadVehicle roadVehicle=new RoadVehicle();
roadVehicle.run("火车");
AirVehicle airVehicle=new AirVehicle();
airVehicle.run("飞机");
}
}
class RoadVehicle{
public void run(String vehicle){
System.out.println(vehicle+"在陆地上运行·");
}
}
class AirVehicle{
public void run(String vehicle){
System.out.println(vehicle+"在天空上运行·");
}
}
在方法上遵守单一原则
public class SingleResponsibility3 {
public static void main(String[] args) {
Vehicle2 vehicle2=new Vehicle2();
vehicle2.roadRun("火车");
vehicle2.airRun("飞机");
}
}
class Vehicle2{
public void roadRun(String vehicle){
System.out.println("在陆地上运行");
}
public void airRun(String vehicle){
System.out.println("在天空上面运行");
}
}
2.接口隔离:一个类实现的接口的方法通常都不会有冗余的方法,也就是每个方法都要实现,如果有的方法没有实现,那么就要拆分这个接口。
public class Segregation1 {
public static void main(String[] args) {
A a=new A();
a.method1(new B());
a.method2(new B());
a.method3(new B());
C c=new C();
c.method1(new D());
c.method2(new D());
c.method3(new D());
}
}
interface InterFace1{
void method1();
}
interface InterFace2{
void method2();
void method3();
}
interface InterFace3{
void method4();
void method5();
}
class B implements InterFace1,InterFace2{
@Override
public void method1() {
System.out.println("B 实现了1");
}
@Override
public void method2() {
System.out.println("B 实现了2");
}
@Override
public void method3() {
System.out.println("B 实现了3");
}
}
class D implements InterFace1,InterFace3{
@Override
public void method1() {
System.out.println("D 实现了1");
}
@Override
public void method4() {
System.out.println("D 实现了4");
}
@Override
public void method5() {
System.out.println("D 实现了5");
}
}
class A{
public void method1(InterFace1 interFace1){
interFace1.method1();
}
public void method2(InterFace2 interFace1){
interFace1.method2();
}
public void method3(InterFace2 interFace1){
interFace1.method3();
}
}
class C{
public void method1(InterFace1 interFace1){
interFace1.method1();
}
public void method2(InterFace3 interFace1){
interFace1.method4();
}
public void method3(InterFace3 interFace1){
interFace1.method5();
}
}
3.依赖倒转:尽量依赖上层的类和抽象类和接口来实现功能。意思就是实现一个功能如果是写一个具体的类,那么修改的时候就要写一个新的类,但是如果这个时候我们实现这个功能,只需要实现一个接口,或者继承一个抽象类就能够重写某个方法,并且由自己来定义,那么修改就会变得更方便,给与了类修改的缓冲,而且稳定性更好,不需要直接修改接口,而是继承、实现来修改方法
下面这个代码的意思,其实就是为了实现接收信息的功能,微信接收,普通接收,只需要直接实现接口IReceiver就可以了,而且能够通过接收实现这个接口的类来执行对应功能。
public class Dependency1 {
public static void main(String[] args) {
Person p=new Person();
p.receive(new Email());
p.receive(new WeiXin());
}
}
interface IReceiver{
String getInfo();
}
class WeiXin implements IReceiver{
@Override
public String getInfo() {
return "我是微信信息";
}
}
class Email implements IReceiver{
public String getInfo(){
return "返回信息";
}
}
class Person{
public void receive(IReceiver receiver){
String info = receiver.getInfo();
System.out.println(info);
}
}
4.里氏替换:父类方法不影响子类。可以通过中间一个基类来完成这样的过渡。如果子类要用到父类方法,可以使用组合、聚合、依赖等
public class Liskov {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
System.out.println("11-3=" + a.func1(11, 3));
System.out.println("1-8=" + a.func1(1, 8));
System.out.println("-----------------------");
B b = new B();
System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11-3
System.out.println("1+8=" + b.func1(1, 8));// 1-8
System.out.println("11+3+9=" + b.func2(11, 3));
System.out.println("11-3="+b.fun3(11,3));
}
}
class Base{
}
// A类
class A extends Base{
// 返回两个数的差
public int func1(int num1, int num2) {
return num1 - num2;
}
}
// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends Base {
private A a1=new A();
//这里,重写了A类的方法, 可能是无意识
public int func1(int a, int b) {
return a + b;
}
public int func2(int a, int b) {
return func1(a, b) + 9;
}
public int fun3(int a,int b ){
return a1.func1(a,b);
}
}
5.开闭原则ocp:提供方开放拓展功能,使用方修改关闭,意思其实就是提供方可以拓展功能,但是拓展功能之后使用方是不可以对自己的方法进行修改。
下面代码拓展绘制图形只需要提供方拓展类就行,editor也就是使用方永远只有一个方法。
public class Ocp {
public static void main(String[] args) {
//使用看看存在的问题
GraphicEditor graphicEditor = new GraphicEditor();
graphicEditor.drawShape(new Rectangle());
graphicEditor.drawShape(new Circle());
graphicEditor.drawShape(new Triangle());
graphicEditor.drawShape(new OtherGraph());
}
}
//这是一个用于绘图的类 [使用方]
class GraphicEditor {
//接收Shape对象,然后根据type,来绘制不同的图形
public void drawShape(Shape s) {
s.draw();
}
}
//Shape类,基类
abstract class Shape {
int m_type;
public abstract void draw();
}
class Rectangle extends Shape {
Rectangle() {
super.m_type = 1;
}
@Override
public void draw() {
System.out.println("绘制一个长方形");
}
}
class Circle extends Shape {
Circle() {
super.m_type = 2;
}
@Override
public void draw() {
System.out.println("绘制一个圆形");
}
}
//新增画三角形
class Triangle extends Shape {
Triangle() {
super.m_type = 3;
}
@Override
public void draw() {
System.out.println("绘制一个三角形");
}
}
class OtherGraph extends Shape{
OtherGraph(){super.m_type=4;}
@Override
public void draw() {
System.out.println("绘制其它图形");
}
}
**6.迪米特法则:最少知道原则,不能够在方法中调用不是直接朋友的类,这些类的属性和方法一定是封装自身类中,而不是在别的类展示。 **
直接朋友
其实就是方法中接收的类 ,返回的类等。
而不是直接朋友的类就是那些局部变量,直接调用的类。
//客户端
public class Demeter1 {
public static void main(String[] args) {
//创建了一个 SchoolManager 对象
SchoolManager schoolManager = new SchoolManager();
//输出学院的员工id 和 学校总部的员工信息
schoolManager.printAllEmployee(new CollegeManager());
}
}
//学校总部员工类
class Employee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//学院的员工类
class CollegeEmployee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//管理学院员工的管理类
class CollegeManager {
//返回学院的所有员工
public List<CollegeEmployee> getAllEmployee() {
List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
CollegeEmployee emp = new CollegeEmployee();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
public void printAll(){
//获取所有员工,然后进行输出,这些都是应该出现在类里面。
List<CollegeEmployee> list1 = this.getAllEmployee();
System.out.println("------------学院员工------------");
for (CollegeEmployee e : list1) {
System.out.println(e.getId());
}
}
}
//学校管理类
//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
class SchoolManager {
//返回学校总部的员工
public List<Employee> getAllEmployee() {
List<Employee> list = new ArrayList<Employee>();
for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
Employee emp = new Employee();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
//该方法完成输出学校总部和学院员工信息(id)
void printAllEmployee(CollegeManager sub) {
//分析问题
//1. 这里的 CollegeEmployee 不是 SchoolManager的直接朋友
//2. CollegeEmployee 是以局部变量方式出现在 SchoolManager
//3. 违反了 迪米特法则
//获取到学院员工
sub.printAll();
//获取到学校总部员工
List<Employee> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工------------");
for (Employee e : list2) {
System.out.println(e.getId());
}
}
}
7.合成复用法则:松耦合的使用方式。如果要使用别的类最好就是组合,聚合,依赖等方式使用。
单例模式
单例模式分为饿汉式和懒汉式,饿汉式其实就是每次都会创建一个新的对象,懒汉式呢就是每次对象是空的时候才会创建。饿汉式是线程安全的,但是懒汉式由于多了一个判断所以并不是线程安全的。
饿汉式第一种写法,静态常量,直接new出来。好处是很简单,但是问题就是浪费内存,每次都需要创建一个新的对象
public class Single1 {
public static void main(String[] args) {
Single2 single1 = Single2.getInstance();
Single2 single2 = Single2.getInstance();
System.out.println(single1==single2);
}
}
class Single2{
public final static Single2 SINGLE2=new Single2();
public static Single2 getInstance() {
return SINGLE2;
}
private Single2() {
}
}
饿汉式第二种写法,初始化放在static块里
public class SingletonTest {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1==instance2);
}
}
class Singleton{
public static Singleton singleton;
static {
singleton=new Singleton();
}
public static Singleton getInstance() {
return singleton;
}
private Singleton() {
}
}
懒汉式第一种写法,线程不安全。
public class SingletonTest2 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1==instance2);
}
}
class Singleton{
private static Singleton singleton;
public static Singleton getInstance() {
if(singleton==null) {
singleton=new Singleton();
}
return singleton;
}
private Singleton() {
}
}
懒汉式第二种写法,线程安全,但是由于每次都需要进行同步和判断,效率非常低。
public class SingletonTest3 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1==instance2);
}
}
class Singleton{
private static Singleton singleton;
public static synchronized Singleton getInstance() {
if(singleton==null) {
singleton=new Singleton();
}
return singleton;
}
private Singleton() {
}
}
懒汉式第三种写法,双重检查。其实就是先检查一次对象是否为空,然后进入到同步代码块再次检查是否为空。好处就是第一次检查不是同步的,所以如果对象创建之后只需要判断一次,效率很高。第二次就是专门判断对象为空的时候的创建对象,并且处于同步代码块中,可以解决线程安全的问题。
public class SingletonTest5 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1==instance2);
}
}
class Singleton{
private static volatile Singleton singleton;
public static Singleton getInstance() {
if(singleton==null) {
synchronized (Singleton.class) {
if(singleton==null) {
singleton=new Singleton();
}
}
}
return singleton;
}
private Singleton() {
}
}
懒汉式第四种写法,使用内部类完成初始化。因为内部类在当前类加载的时候是不会加载内部类的属性,直到调用内部类的方法或者属性的时候这个属性才会创建。线程安全,而且效率非常高。
public class SingletonTest6 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1==instance2);
}
}
class Singleton{
private static class SingletonInstance{
private final static Singleton SINGLETON=new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.SINGLETON;
}
private Singleton() {
}
}