设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码,让代码更容易被他人理解,保证代码可靠性。设计模式与己于人都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实种都有相应的原理来与之对应,每种模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是被广泛应用的原因。总体来说,设计模式分为三大类:
(1)开闭原则
开闭原则指的是对外扩展开放,对修改关闭。在对程序进行扩展的时候,不能去修改原有的代码,想要达到这样的效果,我们就需要使用接口或者抽象类。
(2)依赖倒置原则
依赖倒置原则是开闭原则的基础,指的是针对接口编程,依赖抽象而不依赖于具体
(3)里氏替换原则
里氏替换原则是继承与复用的基石,只有当子类可以替换掉基类,且系统的功能不受影响时,基类才能被复用,而子类也能够在基础类上增加新的行为。所以里氏替换原则指的是任何基类可以出现的地方,子类一定可以出现
里氏替换原则是对“开闭原则”的补充,实现“开闭原则”的关键步骤就是抽象化,而基类与子类的继承关系就是抽线化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。
(4)接口隔离原则
使用多个隔离的接口,比使用单个接口要好,降低接口之间的耦合度与依赖,方便升级与维护
(5)迪米特原则
也叫少知道原则,指的是一个类应当尽量减少与其他实体进行相互作用,使得系统宫嗯那个模块相对堵路,降低耦合关系。该原则的初衷是价格年底类的耦合,虽然可以避免与非直接的类通信,但是要通信,就必然会通过一个“中介”来发生关系,过分使用迪米特原则,会产生大量的中介和传递类,导致系统复杂度变大,所以采用迪米特法则要反复权衡,既要做到结构清晰,又要高内聚低耦合
(6)合成复用原则
尽量使用组合/聚合的方式,而不是使用继承
定义一个工厂类,根据传入的参数的值不同返回不同的实例。被创建的实例具有共同的父类或接口(因为函数返回值需要相同,多态)。适用于
1)需要创建的对象较少,
2)客户端不关心对象的创建过程。
优点:可以对创建的对象进行“加工”,对客户端隐藏相关细节;
缺点:因创建逻辑复杂创建对象过多而造成代码臃肿,增加、删除某个子类均会违反开闭原则。
我:对于不同品牌的产品,令该产品类继承一个通用产品类,利用工厂类的静态方法,通过输入型号即可获取对应品牌的产品实例。
public interface Mouse {
void sayHi();
}
public class DellMouse implements Mouse {
@Override
public void sayHi(){
System.out.println("我是dell鼠标");
}
}
public class HpMouse implements Mouse {
@Override
public void sayHi(){
System.out.println("我是hp鼠标");
}
}
public class MouseFactory{
public static Mouse creat(int type) {
switch(type) {
case 0: return new DellMouse();
case 1: return new HpMouse();
default: return new DellMouse();
}
}
}
public static void main (String[] args) {
Mouse mouse = MouseFactory.creatMouse(1);
mouse.sayHi();
}
定义一个用于创建对象的接口,让子类决定实例化哪一个类(不同的对象采用不同的工厂,dell鼠标,有dell工厂生产).对类的实例化延迟到其子类中 .优点:
1)遵循开闭原则;
2)对客户端隐藏对象创建细节;
3)遵循单一职责。
缺点:
1)添加子类的时候“拖家带口”;
2)只支持同一类产品的创建
我:不同品牌的产品仍继承一个通用产品类不变,对于工厂类,为了避免新增一个品牌的产品就要去修改工厂类的代码(加一个产品创建的逻辑),所以将工厂类抽象出来作为一个工厂的接口,当要生产不同品牌的产品时,直接新建一个不同品牌的工厂去创建即可。
public interface MouseFactory {
Mouse creatMouse();
}
public class HpMouseFactory implements MouseFactory {
@Override
public Mouse creatMouse(){
return new HpMouse();
}
}
public class DellMouseFactory implements MouseFactory {
@Override
public Mouse creatMouse(){
return new DellMouse();
}
}
public class FactoryMethodDemo{
public static void main(String[] args) {
MouseFactory mf = new HpMouseFactory();
Mouse mouse = mf.creatMouse();
mouse.syaHi();
}
}
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,抽象工厂模式侧重同一产品族(dell的鼠标和键盘),工厂方法模式更加侧重于同一产品等级(dell的鼠标。没有键盘)。优点:
1)解决了工厂模式只支持生产一种产品的弊端;
3)新增一个产品族(品牌),只需要增加一个新的具体工厂,不需要改代码。
缺点:
1)添加新产品时,依旧违背开闭原则,增加系统复杂度。(Spring结合了工厂模式和反射机制的SpringIOC容器)
我:在工厂模式的基础上,新增一个品牌对应的不同的产品,在工厂接口中增加创建不同产品的抽象方法,不同品牌的工厂子类去实现这些方法。
public interface Keyboard {
void syaHello();
}
public interface Mouse {
void syaHi();
}
public class HpKeyboard implements Keyboard {
@Override
public void sayHello(){
System.out.println("我是惠普键盘 ");
}
}
public class DellKeyboard implements Keyboard {
@Override
public void sayHello(){
System.out.println("我是戴尔键盘 ");
}
}
public class HpMouse implements Mouse {
@Override
public void sayHi(){
System.out.println("我是惠普鼠标 ");
}
}
public class DellMouse implements Mouse {
@Override
public void sayHi(){
System.out.println("我是戴尔鼠标");
}
}
public interface Computerfactory {
Mouse creatMouse();
Keyboard creatKeyBoard();
}
public class DellComputerFactory implements ComputerFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public Keyboard creatKeyBoard() {
return new DellKeyboard();
}
}
public class HpComputerFactory implements ComputerFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
@Override
public Keyboard creatKeyBoard() {
return new HpKeyboard();
}
}
public class AbstractFactoryDemo {
public static void main(String[] args) {
ComputerFactory cf = new HpComputerfactory();
Mouse mouse = cf.createMouse();
Keyboard ketboard = cf.createKeyboard();
mouse.syaHi();
Keyboard.say.hello();
}
}
建造者模式将复杂产品的创建过程步骤分解在不同的方法中,使得创建过程更加清晰,从而更精确控制复杂对象的生产过程;通过隔离复杂对象的构建与使用,也就是将产品的创建与产品本身分离开来,使得同样的构建过程可以创建不同的对象;并且每个建造者都相互独立,因此可以很方便地替换具体建造者或则增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
KFC里面一般都有好几种可供客户选择的套餐,它可以根据用户所点的套餐,然后再后面做这些套餐,返回给客户的是一个完整的套餐,下面我们将会模拟这个过程,我们约定套餐主要包含汉堡,薯条,可乐,鸡腿等组成部分,使用不同的组成部分就可以构建出不同的套餐。
我:抽象出一个建造类的抽象类,对于要生成的不同对象新建不同的子类继承建造类的抽象类。最后控制者,会直接利用抽象类根据传入的不同子类实现创建不同的对象。
public class Meal {
private String food;
private String drink;
public String getFood() {
return food;
}
public void setFood(String food) {
this.food = food;
}
public String getDrink() {
return drink;
}
public void setDrink(String drink) {
this.drink = drink;
}
}
public abstract class MealBuilder {
Meal meal = new Meal();
public abstract void buildFood();
public abstract void buildDrink();
public Meal getMeal(){
return meal;
}
}
public class MealA extends MealBuilder{
public void buildDrink() {
meal.setDrink("一杯可乐");
}
public void buildFood() {
meal.setFood("一盒薯条");
}
}
public class MealB extends MealBuilder{
public void buildDrink() {
meal.setDrink("一杯柠檬果汁");
}
public void buildFood() {
meal.setFood("三个鸡翅");
}
}
public class KFCWaiter {
private MealBuilder mealBuilder;
public void setMealBuilder(MealBuilder mealBuilder) {
this.mealBuilder = mealBuilder;
}
public Meal construct(){
//准备食物
mealBuilder.buildFood();
//准备饮料
mealBuilder.buildDrink();
//准备完毕,返回一个完整的套餐给客户
return mealBuilder.getMeal();
}
}
public class Client {
public static void main(String[] args) {
//服务员
KFCWaiter waiter = new KFCWaiter();
//套餐A
MealA a = new MealA();
//服务员准备套餐A
waiter.setMealBuilder(a);
//获得套餐
Meal mealA = waiter.construct();
System.out.print("套餐A的组成部分:");
System.out.println(mealA.getFood()+"---"+mealA.getDrink());
}
}
单例模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他途径访问该实例。单例模式的优点在于:
Singleton通过私有化构造函数,避免类在外部被实例化,而且只能通过getInstance()方法获取Singleton的唯一实例。但是以上懒汉式单例的实现是线程不安全的,在并发环境下可能出现多个Singleton实例的问题
public class Singlgton {
//懒汉模式,在第一次调用时候实例化自己
private Singleton(){};
private static Singleton single = null;
//静态工厂方法
public static Singleton geInstance(){
if (single == null) {
single = new Singleton();
}
return single;
}
}
为了实现线程安全,采用单例双重检测的方式
public class Singleton {
private Singleton(){};
private static volatile Singleton singleton = null;
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
原型模式也是用于对象的创建,通过将一个对象作为原型,对其进行复制克隆,产生一个与原对象类似的新对象。
在java中,原型模式的核心就是原型类Prototype,Protype类需要具备以下两个条件:
Object类中的clone()方法默认是浅拷贝,如果想要深拷贝对象,则需要clone()方法中定义自己的复制逻辑。
使用原型模式进行创建对象不仅简化对象的创建步骤,还比new方式创建对象的性能要好的多,因为Object类的clone()方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能非常查差。
protected的可见范围是在该包范围内以及继承其的子类可见
public class Cow implements Cloneable{
private String name;
private int age;
public Cow(String name, int age) {
this.name = name;
this.age = age;
}
//无引用类型,直接clone即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); //直接抛出了,没用try-catch
}
@Override
public String toString() {
return "Cow{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Sheep implements Cloneable{
private String name;
private int age;
public Cow friend;//新朋友Cow对象,其余不变
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//完成对基本数据类型(属性)和String的克隆
deep = super.clone();
//对引用类型的属性,进行再次clone
Sheep sheep = (Sheep)deep;
sheep.friend = (Cow)friend.clone();
return sheep;
}
public Sheep(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheepDolly=new Sheep("Dolly",2);
sheepDolly.friend=new Cow("Tom",1); //并实例化朋友
Sheep sheep1 = (Sheep)sheepDolly.clone();
Sheep sheep2 = (Sheep)sheepDolly.clone();
Sheep sheep3 = (Sheep)sheepDolly.clone();
//....
System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'\n');
System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode());
System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'\n');
System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode());
System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'\n');
//...
}
}

动态代理的内容https://blog.csdn.net/zpf336/article/details/82751925
https://mingyang.blog.csdn.net/article/details/80981004?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-80981004-blog-106661697.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-80981004-blog-106661697.pc_relevant_paycolumn_v3&utm_relevant_index=2
[https://mingyang.blog.csdn.net/article/details/80981004?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-80981004-blog-106661697.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-80981004-blog-106661697.pc_relevant_paycolumn_v3&utm_relevant_index=2]
代理模式的定义:由于某些原因需要给对象提供一个代理以控制该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
在日常生活中,我们进行手机支付,这个过程设计到从银行取钱,以及将钱打到收款方的账户,我们作为使用者,不需要这些冗余的操作,这些操作完全交给支付平台去搞定。
public interface Payment{
public void pay(){};
}
public class RealPay implements Payment{
@Override
public void pay(){
System.out.println("作为用户,只关心支付,不关心过程");
}
}
public class AliPay implements Payment{
private Payment payment;
public AliPay(Payment payment) {
this.payment = payment;
}
private void beforePay() {
System.out.println("从银行取款");
}
@Override
public void pay() {
beforePay();
payment.pay();
afterPay();
}
private void afterPay() {
System.out.println("将钱打给收款方");
}
}
子系统的外部与其内部的通信必须通过统一的对象进行。提供一个高层次的接口,使得子系统更易于使用。优点:

public class LabourContractor {
private Mason woker1 = new Mason();
private BrickWorker woker2 = new BrikWorker();
private BrikLayer woker3 = new BrikLayer();
public void buildHouse(){
worker1.mix();
woker2.carry();
woker3.neat();
}
}
public class Client{
LabourContractor labourContractor = new LabourContractor();
labourContractor.buildHouse();
}
围绕抽象类,实现通用逻辑,定义模板结构,部分逻辑由子类实现,其特点:
public abstract class KTYRoom {
public void procedure(){
openDevice();
orderSong();
orderExtra();
pay();
}
//模板自带方法,使用前必须得打开设备
private void openDevice() {
Systrm.out.println("打开视频和音响");
}
//子类必须实现的方法,必须得选歌
protected abstract void orderSong();
//钩子,额外开销视情况而定
protected void orderExtra();
//模板自带方法,用后必须付款
private void pay() {
Systrm.out.println("付款");
}
}
public ZhangSan extends KTYRoom {
@Override
protected void orderSong(){
System.out.println("82年拉菲")
}
@Override
protected void orderExtra(){
System.out.println("来一份果盘");
}
}
public LiSi extends KTYRoom {
@Override
protected void orderSong(){
System.out.println("82年雪碧");
}
// 不要额外消费
}
观察者模式又称为发布-订阅模式,定义了对象之间的一对多依赖关系。当目标对象(被观察者)的状态发生变化时,他的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以能够根据需求增加和删除观察者,使得系统易于扩展,符合开闭原则。并且观察者模式让目标对象和观察者松耦合,虽然彼此不清楚对方的细节,但是依然可以交互,目标对象只知道一个具体的观察者列表,但并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。
但观察者模式的缺点在于如果很多个被观察者的话,那么嫁给你需要花费一定时间通知所有的观察者,如果观察者和被观察者之间存在循环依赖的话,那么可能导致系统崩溃,并且观察者模式没有相应的机制让观察者知道被观察者是怎么发生变化的,而仅仅只是知道观察目标发生变化。
情景:在气象观测站中,他能够追踪目前的天气情况,包括温度,适度,气压。需要实现一个布告板,能够分别显示目前的状态,气象统计和简单的预报。当气象站中获取最新的测量数据时,三种布告板必须实时更新。
public interface Subject {
//注册观察者
public void registerObserver(Observer observer);
//删除观察者
public void removeObserver(Observer observer);
//当主题状态发生改变时,这个方法需要被调用,以通知所有观察者
public void notifyObserver();
}
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
public interface DisplayElment {
public void display();
}
public WeatherData implements Subject {
private List<Observer> observers;
private float tempterature;
private float pressure;
private float humidty;
public WeatherData(){
observers = new ArrayList<Observer>();
}
@Override
public void notifyObserver() {
for (int i = 0; i < observers.size(); i++) {
Observer observer = observers.get(i);
observer.update(tempterature, pressure, humidty);
}
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Overried
public void removeObserver(Observer observer) {
int i = observers.indexOf(observer);
if (i >= 0) {
observers.remove(i);
}
}
@Override
public void measurementChanged(){
notifyObserver();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementChanged();
}
}
public class CurrentConditionDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temp, float hunidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
@Override
public void display() {
System.out.println("Current conditions:"+temperature+"F degrees and "+humidity+"% humidity");
}
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();//被观察者
CurrentConditionsDisplay conditionsDisplay = new CurrentConditionsDisplay(weatherData);//观察者
weatherData.setMeasurements(80, 65, 30.4f);//被观察者发布信息
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 78, 40.4f);
}
}