设计模式的六大原则
-
单一功能原则(类和方法,接口)
规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分
优点:控制类的粒度大小、将对象解耦、提高其内聚性
-
开闭原则(扩展开放,修改关闭)
通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中
-
里氏替换原则(基类和子类之间的关系)
实现开闭原则的重要方式之一
子类可以扩展父类的功能,但不能改变父类原有的功能
-
依赖倒置原则(依赖抽象接口,而不是具体对象)
实现开闭原则的重要途径之一
使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成
-
接口隔离原则(接口按照功能细分)
尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法
-
迪米特法则(类与类之间的亲疏关系)
果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用
说一下你熟悉的设计模式?
创建性
单例模式
确保一个类只有一个实例,并提供该实例的全局访问点。
// 懒汉式
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// 线程安全懒汉式
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// DCL (Double-checked Locking, 双重检查锁定模式)
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
/*
* 在执行 instance = new Singleton() 时还是有安全问题,JVM 在执行改行代码时会进行分配对象的内存空间、初始化对象、instance 引用分配好的空间,但指令重排后,有可能出现的情况是初始化对象和 instance 引用两条指令交换,导致 instance 引用到未初始化的对象。如果此时刚好有线程访问,那么会直接返回一个未初始化的对象,从而导致线程安全问题的出现。
* 解决方法就是加 volatile 关键字,防止指令重排就好了。
*/
// 静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static synchronized Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
// 饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
// 枚举类:上面几种方法序列化和反序列化会重新创建单例实例,而枚举l
// https://segmentfault.com/a/1190000024472352
简单工厂模式
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口
// 抽象产品
public interface Product {
}
// 具体产品
public class ConcreteProduct1 implements Product {
}
public class ConcreteProduct2 implements Product {
}
// 简单工厂
public class SimpleFactory {
public Product createProduct(int type) {
if (type == 1) {
return new ConcreteProduct1();
}
return new ConcreteProduct2();
}
}
// test
public class Client {
public static void main(String[] args) {
SimpleFactory simpleFactory = new SimpleFactory();
Product product = simpleFactory.createProduct(1);
}
}
工厂方法模式
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象
// 抽象产品
public interface Product {
}
// 具体产品
public class ConcreteProduct1 implements Product {
}
public class ConcreteProduct2 implements Product {
}
// 抽象工厂
public abstract class Factory {
abstract public Product factoryMethod();
public void doSomething() {
Product product = factoryMethod();
}
}
// 具体工厂
public class ConcreteFactory1 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct1();
}
}
public class ConcreteFactory2 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct2();
}
}
// test
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory1();
Product product = factory.create();
}
}
抽象工厂模式
提供一个接口,用于创建 相关的对象家族
与工厂方法模式不同的是,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂生产多个产品
public class AbstractProductA {
}
public class AbstractProductB {
}
public class ProductA1 extends AbstractProductA {
}
public class ProductA2 extends AbstractProductA {
}
public class ProductB1 extends AbstractProductB {
}
public class ProductB2 extends AbstractProductB {
}
public abstract class AbstractFactory {
abstract AbstractProductA createProductA();
abstract AbstractProductB createProductB();
}
public class ConcreteFactory1 extends AbstractFactory {
AbstractProductA createProductA() {
return new ProductA1();
}
AbstractProductB createProductB() {
return new ProductB1();
}
}
public class ConcreteFactory2 extends AbstractFactory {
AbstractProductA createProductA() {
return new ProductA2();
}
AbstractProductB createProductB() {
return new ProductB2();
}
}
public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory = new ConcreteFactory1();
AbstractProductA productA = abstractFactory.createProductA();
AbstractProductB productB = abstractFactory.createProductB();
}
}
生成器模式
封装一个对象的构造过程,并允许按步骤构造
// 抽象建造者
public class AbstractStringBuilder {
protected char[] value;
protected int count;
public AbstractStringBuilder(int capacity) {
count = 0;
value = new char[capacity];
}
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
}
// 具体建造者
public class StringBuilder extends AbstractStringBuilder {
public StringBuilder() {
super(16);
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
}
// test
public class Client {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
final int count = 26;
for (int i = 0; i < count; i++) {
sb.append((char) ('a' + i));
}
System.out.println(sb.toString());
}
}
原型模式
使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象
public abstract class Prototype {
abstract Prototype myClone();
}
public class ConcretePrototype extends Prototype {
private String filed;
public ConcretePrototype(String filed) {
this.filed = filed;
}
@Override
Prototype myClone() {
return new ConcretePrototype(filed);
}
@Override
public String toString() {
return filed;
}
}
public class Client {
public static void main(String[] args) {
Prototype prototype = new ConcretePrototype("abc");
Prototype clone = prototype.myClone();
System.out.println(clone.toString());
}
}
行为型
观察者模式
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者
public interface Person {
// 小王和小李可以通过这个接口接受小美发来的消息
void getMessage(String s)
}
public class XiaoWang implements Person {
private String name = "小王";
public XiaoWang() {}
@Override
public void getMessage(String s) {
System.out.println(name + "接到了小美打过来的电话,电话内容是:" + s);
}
}
public class XiaoLi implements Person {
private String name = "小李";
public XiaoLi() {}
@Override
public void getMessage(String s) {
System.out.println(name + "接到了小美打过来的电话,电话内容是:-->" + s);
}
}
public class XiaoMei {
List<Person> list = new ArrayList<Person>();
public XiaoMei() {}
public void addPerson(Person person) {
list.add(person);
}
// 发消息给备胎
public void notifyPerson() {
for (Person person : list) {
person.getMessage("你们过来吧,谁先过来谁就能陪我一起玩儿游戏!");
}
}
}
public class Test {
public static void main(String[] args) {
XiaoMei xiaoMei = new XiaoMei();
LaoWang xiaoWang = new XiaoWang();
LaoLi xiaoLi = new XiaoLi();
//小王和小李在小美那里都注册了一下
xiaoMei.addPerson(xiaoWang);
xiaoMei.addPerson(xiaoLi);
//小美向小王和小李发送通知
xiaoMei.notifyPerson();
}
}
模板模式
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("boilWater");
}
void pourInCup() {
System.out.println("pourInCup");
}
}
public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Coffee.brew");
}
@Override
void addCondiments() {
System.out.println("Coffee.addCondiments");
}
}
public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Tea.brew");
}
@Override
void addCondiments() {
System.out.println("Tea.addCondiments");
}
}
public class Client {
public static void main(String[] args) {
CaffeineBeverage caffeineBeverage = new Coffee();
caffeineBeverage.prepareRecipe();
System.out.println("-----------");
caffeineBeverage = new Tea();
caffeineBeverage.prepareRecipe();
}
}
策略模式
一个类的行为或其算法可以在运行时更改,创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象
public interface Strategy {
public int doOperation (int num1, int num2);
}
public class OperationAdd {
@Overrride
public int doOperation (int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubtract {
@Overrride
public int doOperation (int num1, int num2) {
return num1 - num2;
}
}
public class Context {
private Strategy strategy;
public Context (Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy (int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
// test
public class Demo {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
}
结构性
装饰者模式
为对象动态添加功能
public class Food {
private String foodName;
public Food() {}
public Food(String foodName) {
this.foodName = foodName;
}
public String make() {
return foodName;
}
}
// 面包类
public class Bread extends Food {
private Food basicFood;
public Bread(Food basicFood) {
this.basicFood = basicFood;
}
public String make() {
return basicFood.make() + "+面包";
}
}
// 奶油类
public class Cream extends Food {
private Food basicFood;
public Cream(Food basicFood) {
this.basicFood = basicFood;
}
public String make() {
return basicFood.make() + "+奶油";
}
}
public class Test {
public static void main(String[] args) {
Food food = new Bread(new Cream(new Food("香肠")));
System.out.println(food.make());
}
}
适配者模式
把一个类接口转换成另一个用户需要的接口
class Phone {
public static final int V = 220;
private VoltageAdapter adapter;
public void charge() {
adapter.changeVoltage();
}
public void setAdapter(VoltageAdapter adapter) {
this.adapter = adapter;
}
}
// 变压器
class VoltageAdapter {
public void changeVoltage() {
System.out.println("正在充电...");
System.out.println("原始电压:" + Phone.V + "V");
System.out.println("经过变压器转换之后的电压:" + (Phone.V - 200) + "V");
}
}
public class Test {
public static void main(String[] args) {
Phone phone = new Phone();
VoltageAdapter adapter = new VoltageAdapter();
phone.setAdapter(adapter);
phone.charge();
}
}
代理模式
控制对其它对象的访问
//代理接口
public interface ProxyInterface {
//需要代理的是结婚这件事
void marry();
}
// 婚庆公司
public class WeddingCompany implements ProxyInterface {
private ProxyInterface proxyInterface;
public WeddingCompany(ProxyInterface proxyInterface) {
this.proxyInterface = proxyInterface;
}
@Override
public void marry() {
System.out.println("我们是婚庆公司的");
System.out.println("我们在做结婚前的准备工作");
System.out.println("节目彩排...");
System.out.println("礼物购买...");
System.out.println("工作人员分工...");
System.out.println("可以开始结婚了");
proxyInterface.marry();
System.out.println("结婚完毕,我们需要做后续处理,你们可以回家了,其余的事情我们公司来做");
}
}
// 结婚家庭
public class NormalHome implements ProxyInterface {
@Override
public void marry() {
System.out.println("我们结婚啦~");
}
}
// Test
public class Test {
public static void main(String[] args) {
ProxyInterface proxyInterface = new WeddingCompany(new NormalHome());
proxyInterface.marry();
}
}
适配器模式,装饰模式,代理模式异同
适配器的特点在于兼容,从代码上的特点来说,适配类与原有的类具有相同的接口,并且持有新的目标对象。就如同一个三孔转2孔的适配器一样,他有三孔的插头,可以插到三孔插座里,又有两孔的插座可以被2孔插头插入。适配器模式是在于对原有3孔的改造。在使用适配器模式的时候,我们必须同时持有原对象,适配对象,目标对象。。。。
装饰器模式特点在于增强,他的特点是被装饰类和所有的装饰类必须实现同一个接口,而且必须持有被装饰的对象,可以无限装饰。
代理模式的特点在于隔离,隔离调用类和被调用类的关系,通过一个代理类去调用。
总的来说就是如下三句话:
- 适配器模式是将一个类(a)通过某种方式转换成另一个类(b).
- 装饰模式是在一个原有类(a)的基础之上增加了某些新的功能变成另一个类(b).
- 代理模式是将一个类(a)转换成具体的操作类(b).
https://www.jianshu.com/p/c156b5e23e30
图说设计模式
https://design-patterns.readthedocs.io/zh_CN/latest/index.html
Reference:
- https://mp.weixin.qq.com/s/Wahq4TnCm4Pzb6VshWma1Q