设计模式

面向对象设计原则

开闭原则(总纲)
扩展,而非修改代码。open for extension, close for modification

里氏替换原则
不要破坏继承关系。子类不要轻易重写父类方法,而是提供新的方法,以防在替换父类时产生异常。

依赖倒置原则
面向接口编程。依赖抽象而非具体(向宏观依赖)。如:方法定义的参数类型为接口类型,实际参数可以传其子类

单一职责原则
实现类要职责单一,功能拆分,以防依赖这个类需要引入许多无关的东西,以便降低颗粒度提高复用性。

接口隔离原则
接口功能要精简单一,可拆分为多个模块,不要试图用一个接口囊括满足所有需要实现的方法

迪米特法则
降低耦合度。没有直接关联的对象之间不要直接互相调用,而是通过中间类。(例:民众与政府之间通过政府机构产生关联,办事、意见建议等通过机构中间类进行)(缺点:产生过多中间类)

合成复用原则
优先通过组合关系而非继承关系(耦合度太高)实现复用(如:不要用黄苹果红苹果继承苹果类,而是给苹果一个颜色作为成员对象(属性),这样增加绿苹果白苹果等就不用修改代码。)

单例模式

概念

一个项目工程中某个资源只创建1个实例对象;

构造函数私有化;
在本类中创建私有的静态本类对象;
提供静态的方法返回这个静态本类对象,以确保对象唯一;

使用场景

一般实体类对象不会用单例模式,类似 打印机、 等才会使用单例,因为只需要共享一份资源实例就好。

饿汉式(立即加载)

在这里插入图片描述
缺点——可能 浪费资源 过早创建本类对象

优点——线程安全 的;高效

懒汉式(延迟加载)

常规模式

在这里插入图片描述
缺点——线程不安全

优点——避免了类被加载时就创建对象导致的资源浪费

线程安全的懒汉式

在获取实例对象的方法声明中 添加 synchronize 关键字 / 将判断并创建实例对象的代码放入synchronized 代码块(确保线程安全

在这里插入图片描述

推荐在实例对象前加volatile
volatile:可见的
确保其修饰的对象,每一次被读写都是对其他线程可见的
(其他线程即刻收到通知知晓自己的内存地址已经失效,避免多线程下的线程不安全)

创建型模式-对创建对象封装

含义:负责创建对象,将对象的创建和使用分离;不需要知道怎么创建,得到对象即可。

单例singleton

含义

只提供一个对象

基本结构

	私有化的构造函数
	公开的newInstance方法,返回本类对象

使用场景

线程池对象的创建、类似scanner、random、inputstream等只需创建一个,可一直复用的对象的创建

注意事项

在多线程中需要注意线程同步问题导致创建出多个对象(使用非空判断进行延迟加载、使用synchronize进行同步机制)

分类

饿汉式

public class HungrySingleton {
	private static final String filed1 = "a";
	private static final int filed2 = new Random().nextInt(10);
	//静态,类加载时就创建了对象
	private static HungrySingleton hs = new HungrySingleton();
	//构造函数必须私有化
	private  HungrySingleton() {
	}
	
	public static String getFiled1() {
		return filed1;
	}

	public static int getFiled2() {
		return filed2;
	}
	//调用方法的时候直接返回创建好的对象
	public static HungrySingleton getSingletonInstance() {
		return hs;
	}
}

懒汉式+线程同步

public class LazySingleton {
	private static final String filed1 = "a";
	private static final int filed2 = new Random().nextInt(10);
	private static LazySingleton ls = null;
	//私有化构造函数
	private  LazySingleton() {
	}
	
	public static String getFiled1() {
		return filed1;
	}

	public static int getFiled2() {
		return filed2;
	}

	//方法增加线程同步的关键字,成为同步方法(锁是this)
	public synchronized static LazySingleton getSingletonInstance() {
		//非空判断,用于延迟加载,非空才创建,已有则不创建
		if(ls == null){
			ls= new LazySingleton();
		}
		return ls;
	}
}

原型proto

含义

使用一次new调用构造方法+多次clone方法,获得多个类似的某类对象

基本结构

	原型类实现cloneable接口并重写clone方法
	创建时先调用构造函数new一个原型类对象,并不断调用clone方法获得多个相同或类似的对象(属性相同,地址值不同)

使用场景

创建的对象之间重叠度较高,直接创建一个原型然后复制,比重新创建效率更高的时候

分类

原型模式

public class student implements Cloneable{
	private String name;
	private int id = new Random().nextInt(10)+10;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	public student(String name) {
		super();
		this.name = name;
		this.id = new Random().nextInt(10)+10;
	}
	
	public student clone() {
		student c2 = null;
		try {
			 c2=(student) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return c2;
	}

	public void gotoschool() {
		System.out.println(this);
		System.out.println(this.name + "去上学了,他的学号是:" + this.id);
	}
}
//对象地址不同但属性相同
public class Demo {
	public static void main(String[] args) {
		student s = new student("小李");
		student s2 = s.clone();
		student s3 = s.clone();
		student s4 = s2.clone();
		
		s.gotoschool();
		//com.study.clone.student@7852e922
		//小李去上学了,他的学号是:17
		s2.gotoschool();
		//com.study.clone.student@4e25154f
		//小李去上学了,他的学号是:17
		s3.gotoschool();
		//com.study.clone.student@70dea4e
		//小李去上学了,他的学号是:17
		s4.gotoschool();
		//com.study.clone.student@5c647e05
		//小李去上学了,他的学号是:17
	}
}

带管理器的原型模式(new对象的动作彻底从调用时剥离,转到管理者处)
一个接口本身实现cloneable接口并定义clone()方法,其实现类都重写clone()方法。

创建一个ProtoManager类,其核心对象是一个以类名为键,类对象为值的Map

在该类的构造器中,初始化这个map(将这些实现类的类名和new的对象放入map)

然后提供一个getInstance方法,根据类名从map中获取类对象的clone对象(new出来的只有一个,外部调用getInstance得到的都是clone的对象且都是不同的地址)

public interface SchoolMember extends Cloneable {
	void gotoschool();
	SchoolMember clone();
}

public class student implements Cloneable,SchoolMember{
	private String name;
	private int id = new Random().nextInt(10)+10;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	public student(String name) {
		super();
		this.name = name;
		this.id = new Random().nextInt(10)+10;
	}
	
	public student clone() {
		student c2 = null;
		try {
			 c2=(student) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return c2;
	}

	public void gotoschool() {
		System.out.println(this);
		System.out.println(this.name + "去上学了,他的学号是:" + this.id);
	}
}

public class teacher implements Cloneable,SchoolMember{
	private String name;
	private String subject;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSubject() {
		return subject;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	
	public teacher(String name, String subject) {
		super();
		this.name = name;
		this.subject = subject;
	}
	
	public teacher clone() {
		teacher c2 = null;
		try {
			 c2=(teacher) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return c2;
	}
	public void gotoschool() {
		System.out.println(this);
		System.out.println(this.name + "去教课了,他教的科目是:" + this.subject);
	}
}

public class ProtoManager {
	private Map<String, SchoolMember>ProtoMap = new HashMap<String, SchoolMember>();

	public ProtoManager() {
		ProtoMap.put("student", new student("小张"));
		ProtoMap.put("teacher", new teacher("老王", "数学"));
	}
	
	public SchoolMember getProtoTypeSchoolMember(String key) {
		return ProtoMap.get(key).clone();
	}
}
//测试结果:得到的对象具有相同属性值而地址值不同
public class Demo {
	public static void main(String[] args) {
		ProtoManager pm = new ProtoManager();
		student s = (student)pm.getProtoTypeSchoolMember("student");
		teacher t = (teacher)pm.getProtoTypeSchoolMember("teacher");
		student s1 = (student)pm.getProtoTypeSchoolMember("student");
		teacher t1 = (teacher)pm.getProtoTypeSchoolMember("teacher");
		student s2 = s1.clone();
		teacher t2 = t1.clone();
		student s3 = s1.clone();
		teacher t3 = t1.clone();
		s.gotoschool();
		//com.study.clone.student@7852e922
		//小张去上学了,他的学号是:16
		t.gotoschool();
		//com.study.clone.teacher@4e25154f
		//老王去教课了,他教的科目是:数学
		System.out.println("-----------------");
		s1.gotoschool();
		//com.study.clone.student@70dea4e
		//小张去上学了,他的学号是:16
		t1.gotoschool();
		//com.study.clone.teacher@5c647e05
		//老王去教课了,他教的科目是:数学
		System.out.println("-----------------");
		s2.gotoschool();
		//com.study.clone.student@33909752
		//小张去上学了,他的学号是:16
		t2.gotoschool();
		//com.study.clone.teacher@55f96302
		//老王去教课了,他教的科目是:数学
		System.out.println("-----------------");
		s3.gotoschool();
		//com.study.clone.student@3d4eac69
		//小张去上学了,他的学号是:16
		t3.gotoschool();
		//com.study.clone.teacher@42a57993
		//老王去教课了,他教的科目是:数学
	}
}

工厂方法FactoryMethod

含义

将产品的创建放在具体工厂类,而无需在调用者中new,也不关心创建细节,实现创建与使用分离

基本结构

产品类,及多种产品类的共同抽象接口
工厂类,及多种工厂类的共同抽象接口
配置文件,及其 读取类(返回一个配置文件所定义的工厂对象)

使用场景

多种同类对象,分别有不同的工厂,需要动态获取不同类的对象
同时不关心细节,只要拿到对象实例

注意事项

复杂度较高,每增加一类产品要增加一个工厂类
如果不使用抽象工厂统一所有工厂,而是使用一个工厂生产所有类,则就是 简单工厂模式

//抽象产品
public interface Animal {
	void run();
}
//具体产品
public class Horse implements Animal{
	@Override
	public void run() {
		System.out.println("Horse Run !");
	}
	public Horse() {
		super();
		System.out.println("新马出生");
	}
}
public class Pig implements Animal{
	@Override
	public void run() {
		System.out.println("Pig Run !");
	}
	public Pig() {
		super();
		System.out.println("新猪出生");
	}
}
public class Sheep implements Animal{
	@Override
	public void run() {
		System.out.println("Sheep Run !");
	}

	public Sheep() {
		super();
		System.out.println("新羊出生");
	}
}

//抽象工厂
public interface AbstractFactory {
	Animal newInstance();
}
//具体工厂
public class HorseFactory implements AbstractFactory{
	public HorseFactory() {
		super();
		System.out.println("养马场营业");
	}

	public Animal newInstance(){
		return new Horse();
	}
}
public class PigFactory implements AbstractFactory{
	public PigFactory() {
		super();
		System.out.println("养猪场营业");
	}
	public Animal newInstance(){
		return new Pig();
	}
}
public class SheepFactory implements AbstractFactory{
	public SheepFactory() {
		super();
		System.out.println("牧羊村营业");
	}
	public Animal newInstance(){
		return new Sheep();
	}
}

//prperties文件(只需更改此处指定的工厂,即可获得不同的产品)
className=com.study.factory.HorseFactory
//读取配置文件类
public class ReadConfig {
	public static Object ReadConfig(){
		Properties properties = new Properties();
		Object  o = null;
		InputStream i = new ReadConfig().getClass().getClassLoader().getResourceAsStream("animal.properties");
		try {
			properties.load(i);
			String className =(String) properties.get("className");
			Class c = Class.forName(className);
			o = c.newInstance();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return o;
	}
}
//测试类
public class Demo {
	public static void main(String[] args) {
		AbstractFactory o =(AbstractFactory) ReadConfig.ReadConfig();
		Animal a = o.newInstance();
		a.run();
	}
}
//养马场营业
//新马出生
//Horse Run !

抽象工厂AbstractFactory

含义

工厂方法模式的拓展升级

基本结构

	产品类,及多种产品类的共同抽象接口
	工厂类,及多种工厂类的共同抽象接口
	配置文件,及其 读取类(返回一个配置文件所定义的工厂对象)

与工厂方法的区别是,一次生产多种同族(同属于一个接口下的)产品
在这里插入图片描述

使用场景

一次只使用一个产品族的产品的场景(因为根据配置文件指定创建的产品族)(但可能使用多种)

注意事项

增加产品类下的产品种类时将不满足开闭原则(需要修改代码且每个产品类都要改)
增加产品族时满足开闭原则(增加一个产品类及其工厂类即可)

public interface Product {
	public void showName();
	public void growUp();
}
public class Animal implements Product {

	@Override
	public void showName() {
		System.out.println("我是小动物");
	}

	@Override
	public void growUp() {
		System.out.println("小动物长大了");
	}

	public Animal() {
		super();
		System.out.println("小动物出生了");
	}

}
public class Plant implements Product {

	@Override
	public void showName() {
		System.out.println("我是植物");
	}

	@Override
	public void growUp() {
		System.out.println("植物生长了");
		
	}
	public Plant() {
		super();
		System.out.println("植物发芽了");
	}
}
public interface AbstractFarm {
	Plant newPlant();
	Animal newAnimal();
}

public class MyFarm implements AbstractFarm{
	public MyFarm() {
		super();
		System.out.println("我的农场建成");
	}

	@Override
	public Plant newPlant() {
		return new Plant();
	}

	@Override
	public Animal newAnimal() {
		return new Animal();
	}
}

public class YourFarm implements AbstractFarm{
	public YourFarm() {
		super();
		System.out.println("你的农场建成");
	}

	@Override
	public Plant newPlant() {
		return new Plant();
	}

	@Override
	public Animal newAnimal() {
		return new Animal();
	}

}

public class Demo {
	public static void main(String[] args) {
		AbstractFarm o =(AbstractFarm) ReadConfig.ReadConfig();
		Plant a = o.newPlant();
		Animal b = o.newAnimal();
		a.showName();
		b.growUp();
	}
}
//我的农场建成
//植物发芽了
//小动物出生了
//我是植物
//小动物长大了

建造者Builder

含义
对象由多个部件构成,比较复杂。需要组装部件来创建。
使用场景
各部分较稳定,但组合方式变化较大(属性设置频繁且较多)
优点
其中提供一系列set方法,可以使用方法链形式(new XXXBuilder.setA().setB().setC()…),设置属性较为优雅~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值