还待进一步完善
七大原则
- 单一职责
- 接口隔离
- 最小接口
- 依赖倒转
- 抽象不应该依赖细节,细节应该依赖抽象,中心思想是面向接口编程
- 三种实现方式:接口传递、构造方法传递、setter方式传递
- 里氏替换
- 所有引用基类的地方必须透明地使用其子类对象。
- 在子类中尽量不要重写父类的方法
- 继承让两个类的耦合性增强了,在适当情况下,可以通过聚合、组合、依赖来解决问题。
- 开闭原则
- 对扩展开发(对提供方),对修改关闭(对使用方)。软件需要改变时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 迪米特法则
- 最少知道原则,一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管有多么复杂,都尽量将逻辑封装在类的内部,对外除了提供public方法,不对外泄露任何信息。
- 只与直接的朋友通信。直接的朋友:出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部中的类不是直接的朋友。
- 合成复用原则
- 尽量使用合成/聚合的方式,而不是使用继承
UML类图
- 依赖
- 类中用到了对方,那么它们之间就存在依赖关系
- 泛化
- 继承关系,依赖关系的特例
- 实现
- A类实现B接口
- 关联
- 类与类之间的联系,具有单向和双向关系,具有多重性
- 如单向一对一关系,双向一对一关系
- 聚合
- 整体和部分的关系,整体与部分可以分开。是关联关系的特例
- 组合
- 整体和部分的关系,整体与部分不可以分开。
设计模式
设计模式分为三种类型,共23种 1. 创建型模式:单例模式、抽象工厂、原型模式、建造者模式、工厂模式。 2. 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 3. 行为模式:模板方法模式、命令模式、访问者模式、迭代模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式
- 整体和部分的关系,整体与部分不可以分开。
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局控制点.
public class InnerClassSingleton {
/**
* 基于类初始化
*/
private static class InstanceHolder {
public static InnerClassSingleton instance = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance() {
return InstanceHolder.instance;
}
}
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton instance;
private DoubleCheckSingleton() {}
//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
//同时保证了效率, 推荐使用
public static DoubleCheckSingleton getInstance() {
if(instance == null) {
synchronized (DoubleCheckSingleton.class) {
if(instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
//使用枚举,可以实现单例, 推荐
public enum Singleton {
INSTANCE; //属性
public Singleton getInstance() {
return Singleton.INSTANCE;
}
}
工厂模式
针对每一种产品提供一个工厂类,通过不同的工厂实例来创建不同的产品实例
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
抽象工厂模式
应对产品族概念而生,与工厂模式相比,抽象工厂模式是为了应对产品族
提供一个接口,用于创建 相关的对象家族 。
原型模式
- 用原型实例指定创建对象的种类,并通过拷贝这些原型,创建新的对象。
-
允许一个对象创建另一个对象,无序知道创建的细节
- 通过对象的序列化来实现对象的拷贝(推荐)。
class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
//构造器
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class DeepProtoType implements Serializable, Cloneable{
public String name; //String 属性
public DeepCloneableTarget deepCloneableTarget;// 引用类型
public DeepProtoType() {
super();
}
//深拷贝 - 方式 1 使用clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//这里完成对基本数据类型(属性)和String的克隆
deep = super.clone();
//对引用类型的属性,进行单独处理
DeepProtoType deepProtoType = (DeepProtoType)deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone();
// TODO Auto-generated method stub
return deepProtoType;
}
//深拷贝 - 方式2 通过对象的序列化实现 (推荐)
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
// oos = new ObjectOutputStream(new ByteArrayOutputStream());
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
// ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
DeepProtoType copyObj = (DeepProtoType)ois.readObject();
return copyObj;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
// TODO: handle exception
System.out.println(e2.getMessage());
}
}
}
}
装饰者模式
动态的给一个对象添加一些额外的功能。
- 动态地将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则
代理模式
封装被代理对象并限制外界对被代理对象的访问。
interface ITeacherDao {
void teach(); // 授课的方法
void sayHello(String name);
}
class TeacherDao implements ITeacherDao {
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println(" 老师授课中.... ");
}
@Override
public void sayHello(String name) {
// TODO Auto-generated method stub
System.out.println("hello " + name);
}
}
class ProxyFactory {
//维护一个目标对象 , Object
private Object target;
//构造器 , 对target 进行初始化
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象 生成一个代理对象
public Object getProxyInstance() {
//说明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
// TODO Auto-generated method stub
System.out.println("JDK代理开始~~");
//反射机制调用目标对象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
});
}
}
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建目标对象
ITeacherDao target = new TeacherDao();
//给目标对象,创建代理对象, 可以转成 ITeacherDao
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
//通过代理对象,调用目标对象的方法
//proxyInstance.teach();
proxyInstance.sayHello(" tom ");
}
}
模板方法模式
定义一个操作的算法骨架, 并将一些步骤延迟到子类中。
该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大。一般模板方法都加上final关键字,防止子类重写模板方法。
使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤 在实现时可能不同,通常考虑用模板方法模式来处理。
//抽象类,表示豆浆
abstract class SoyaMilk {
//模板方法, make , 模板方法可以做成final , 不让子类去覆盖.
final void make() {
select();
if(customerWantCondiments()) {
addCondiments();
}
soak();
beat();
}
//选材料
void select() {
System.out.println("第一步:选择好的新鲜黄豆 ");
}
//添加不同的配料, 抽象方法, 子类具体实现
abstract void addCondiments();
//浸泡
void soak() {
System.out.println("第三步, 黄豆和配料开始浸泡, 需要3小时 ");
}
void beat() {
System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");
}
//钩子方法,决定是否需要添加配料
boolean customerWantCondiments() {
return true;
}
}
class RedBeanSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
// TODO Auto-generated method stub
System.out.println(" 加入上好的红豆 ");
}
}
class PureSoyaMilk extends SoyaMilk{
@Override
void addCondiments() {
// TODO Auto-generated method stub
//空实现
}
@Override
boolean customerWantCondiments() {
// TODO Auto-generated method stub
return false;
}
}
class PeanutSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
// TODO Auto-generated method stub
System.out.println(" 加入上好的花生 ");
}
}
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//制作红豆豆浆
System.out.println("----制作红豆豆浆----");
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
System.out.println("----制作花生豆浆----");
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
System.out.println("----制作纯豆浆----");
SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
}
}
外观模式
是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
适配器模式
将一个类的接口转换成客户希望的另一个接口表示,目的是兼容性,别名为包装器(Wrapper)。
主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。
//适配器类
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V; // 关联关系-聚合
//通过构造器,传入一个 Voltage220V 实例
public VoltageAdapter(Voltage220V voltage220v) {
this.voltage220V = voltage220v;
}
@Override
public int output5V() {
int dst = 0;
if(null != voltage220V) {
int src = voltage220V.output220V();//获取220V 电压
System.out.println("使用对象适配器,进行适配~~");
dst = src / 44;
System.out.println("适配完成,输出的电压为=" + dst);
}
return dst;
}
}
//适配接口
interface IVoltage5V {
public int output5V();
}
//被适配的类
class Voltage220V {
//输出220V的电压,不变
public int output220V() {
int src = 220;
System.out.println("电压=" + src + "伏");
return src;
}
}
class Phone {
//充电
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压为5V, 可以充电~~");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5V, 不能充电~~");
}
}
}
桥接模式
将抽象部分与实现部分分离,使它们都可以独立的变化
建造者模式
将一个复杂对象的构建与它的表示分离.
观察者模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在它的状态发生变化时,会通知所有的观察者.
享元模式
命令模式
命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间调用关系更加灵活,实现解耦。在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求,同时命令模式也支持可撤销的操作。
- Invoker 发送 Command ,Receiver接受并根据ConcreteCommand调用方法执行。
interface Command {
public void execute();
public void undo();
}
public class NoCommand implements Command {
@Override
public void execute() {
// TODO Auto-generated method stub
}
@Override
public void undo() {
// TODO Auto-generated method stub
}
}
public class LightReceiver {
public void on() {
System.out.println(" 电灯打开了.. ");
}
public void off() {
System.out.println(" 电灯关闭了.. ");
}
}
class LightOffCommand implements Command {
// 聚合LightReceiver
LightReceiver light;
// 构造器
public LightOffCommand(LightReceiver light) {
super();
this.light = light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
// 调用接收者的方法
light.off();
}
@Override
public void undo() {
// TODO Auto-generated method stub
// 调用接收者的方法
light.on();
}
}
class LightOnCommand implements Command {
//聚合LightReceiver
LightReceiver light;
//构造器
public LightOnCommand(LightReceiver light) {
super();
this.light = light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
//调用接收者的方法
light.on();
}
@Override
public void undo() {
// TODO Auto-generated method stub
//调用接收者的方法
light.off();
}
}
public class RemoteController {
// 开 按钮的命令数组
Command[] onCommands;
Command[] offCommands;
// 执行撤销的命令
Command undoCommand;
// 构造器,完成对按钮初始化
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for (int i = 0; i < 5; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
// 给我们的按钮设置你需要的命令
public void setCommand(int no, Command onCommand, Command offCommand) {
onCommands[no] = onCommand;
offCommands[no] = offCommand;
}
// 按下开按钮
public void onButtonWasPushed(int no) { // no 0
// 找到你按下的开的按钮, 并调用对应方法
onCommands[no].execute();
// 记录这次的操作,用于撤销
undoCommand = onCommands[no];
}
// 按下开按钮
public void offButtonWasPushed(int no) { // no 0
// 找到你按下的关的按钮, 并调用对应方法
offCommands[no].execute();
// 记录这次的操作,用于撤销
undoCommand = offCommands[no];
}
// 按下撤销按钮
public void undoButtonWasPushed() {
undoCommand.undo();
}
}
解释器模式
- 在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一棵抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器。
- 指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
状态模式
- 主要用来解决在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以转换
- 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。
策略模式
定义个策略接口,不同的实现类提供不同的具体策略算法, 同时它们之间可以互相替换。
- 定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
- 体现了:第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合、聚合,少用继承。
- JDK中Arrays的Comparator使用了策略模式
简单工厂模式和策略模式的区别
- 策略模式
- 定义个策略接口,不同的实现类提供不同的具体策略算法, 同时它们之间可以互相替换.
- 简单工厂模式
- 定义一个用以创建对象的工厂, 根据不同的条件生成不同的对象
- 简单工厂模式是根据给定的条件返回相应的对象,而策略模式是将不同的策略对象传递给使用者以实现不同策略。
- 在简单工厂模式中实现了通过条件选取一个类去实例化对象,策略模式则将选取相应对象的工作交给模式的使用者,它本身不去做选取工作。