Day7设计模式(七大原则、单例模式总结)

七大原则

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() {
		
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值