一、前言
Java设计模式在平时的开发中起到了至关重要的作用。设计模式的主要目的是: 1、降低耦合度,使得类的修改不至于“牵一发而动全身”。 2、提高可扩展性,新增功能对原有的代码没什么影响 3、提高可复用性,降低过多的使用类时,导致类爆炸的情况 4、提高灵活性,代码能够通过接口灵活调用 5、提高可维护性,修改的地方越少
二、七大原则
1、单一原则:一个类只负责一个职责 2、开闭原则:对修改关闭,对扩展开放 3、里氏替换原则:不要破坏继承关系 4、接口隔离原则:暴露最小接口,避免接口过于臃肿 5、依赖倒置原则:面向抽象编程 6、迪米特法则:尽量不跟陌生人讲话 7、合成复用原则:多使用组合、聚合、少用继承
1、单一原则
一个方法 一个类只负责一个职责,各个职责的程序改动,不影响其它程序,实现 高内聚,低耦合
优点:降低耦合,提高可维护性,对一个类进行单独处理并且不影响其他类
2、开闭原则
对修改关闭,对扩展开放,核心是:抽象化,多态使用 优点:提高可扩展性,提高可维护性,提高可复用性
3、里氏替换原则
所有使用父类的地方,必须能够透明的使用子类对象
例如:父类Animal;子类Dog继承父类Animal,子类Cat继承父类Animal。
Animal animal=new Dog();
Animal animal=new Cat();
当子类重写父类的方法时,则不适合使用里氏替换原则。
4、接口隔离原则
每一个接口承担独立的角色,只干自己该干的事情。 只暴露最小接口,实现类不需要用到实现的方法不要放在接口。
5、依赖倒置原则
指的是面向抽象编程,对抽象类或接口进行依赖,比较灵活。 比如:有抽象类Animal,子类Dog继承父类Animal,子类Cat继承父类Animal。在依赖的时候用抽象类,在使用的时候指定子类
abstract class Animal{
abstract void hello();
}
class Dog extends Animal{
@Override
void hello() {
System.out.println("hello ,I am dog");
}
}
class Cat extends Animal{
@Override
void hello() {
System.out.println("hello ,I am cat");
}
}
class Client{
Animal a;
public Client(Animal a){
this.a=a;
}
public void hello(){
a.hello();
}
}
public class Test {
public static void main(String args[]) {
Client c=new Client(new Dog());
c.hello();
}
}
6、迪米特法则
尽量不要跟陌生人说话。 不是陌生人的情况:
- 当前对象本身(this)
- 方法参数
- 对象的成员对象
- 对象所创建的对象
目的:降低耦合,高内聚
7、合成复用原则
尽量使用组合、聚合的方式,少使用继承。 原因:继承会导致耦合度变高。 聚合方式的使用案例:
class A{}
class Test{
A a;
public void useA(A a){
this.a=a;
}
}
组合方式的使用案例:
class A{}
class Test{
A a=new A();
}
组合和聚合的区别 : 组合方式在使用Test对象的时候会立即开辟A对象的空间,而聚合的方式是在使用到A对象的时候才会开辟A对象的空间。
三、23种设计模式
创建型模式:主要关注点是“怎样创建对象”
1、单例模式(Singleton)
特点:当需求是一个类只需要一个实例 单例模式有:1、饿汉模式;2、懒汉模式;3、双重检查模式;4、枚举模式
饿汉模式(推荐使用)
特点: 当类加载时创建好对象,并且在外部不能通过new创建该对象,只能调用这个类的的方法进行调用。线程安全,在实际开发中用的最多 案例: 方式一
public class Singleton {
private Singleton(){}
private static Singleton instance=new Singleton();
public static Singleton getInstance(){
return instance;
}
}
class Singleton2 {
private static Singleton2 instance;
private Singleton2(){
instance=new Singleton2();
}
public static Singleton2 getInstance(){
return instance;
}
}
class Singleton3 {
private static Singleton3 instance;
static {
instance=new Singleton3();
}
private Singleton3(){}
public static Singleton3 getInstance(){
return instance;
}
}
懒汉模式(不推荐使用)
特点: 等需要该类的时候再加载,会考虑线程安全问题 1、不安全的懒汉模式
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
instance=new Singleton();
return instance;
}
}
class Singleton2{
private static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance(){
if(instance==null){
synchronized(Singleton2.class){
instance=new Singleton2();
}
}
return instance;
}
}
以上代码线程不安全的原因:当几个线程同时访问的时候,就有可能创建多个对象实例。
2、线程安全的懒汉模式
class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
以上代码缺点:当getInstance()方法里面的逻辑代码很复杂时,所有的代码都被加锁,会大大的消耗性能
双重检查懒汉模式(线程安全)
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
静态内部类实现单例
class Singleton{
private Singleton(){}
private static class GetSingleton{
private static final Singleton instance=new Singleton();
}
public Singleton getInstance(){
return GetSingleton.instance;
}
}
运用枚举实现单例(推荐使用)
enum Singleton2{
ONE,TWO,THREE;
}
小结
推荐使用饿汉模式和枚举模式实现单例的原因是线程安全,而且简单明了 不推荐使用懒汉模式的原因是:1、部分的懒汉模式不安全 ;2、过于繁琐 ;3、有可能会对性能造成额外消耗
2、工厂模式(Factoy)
特点:对类的创建用一个工厂类进行管理。
工厂模式分为:简单工厂,工厂方法和抽象工厂,这节内容主要讲简单工厂和工厂方法。
简单工厂
由一个工厂对象决定创建出哪一种产品类的实例 代替构造函数创建对象,方法名比构造函数清晰。 简单工厂的类图:
具体代码实现:
public class SimpleFactory{
public createProduct(int i){
switch (i){
case 0: new Product1();break;
case 1: new Product2();break;
case 2: new Product3();break;
default: System.out.println("没有该产品");
}
}
public static void main(String[] args){
SimpleFactory factory=new SimpleFactory();
factory.createProduct(1);
}
}
class Product1{}
class Product2{}
class Product3{}
工厂方法
abstract class FactoryMethod {
public abstract void production(String productName);
}
class Product1 extends FactoryMethod {
@Override
public void production(String productName) {
System.out.println("Product1生产了"+productName+"产品");
}
}
class Product2 extends FactoryMethod {
@Override
public void production(String productName) {
System.out.println("Product2生产了"+productName+"产品");
}
}
public class Client{
public static void main(String[] args) {
FactoryMethod factory=new Product1();
factory.production("x");
}
}
3、抽象工厂模式(AbstractFactory)
创建一组有关联的对象实例
角色:
- AbstractProduct (抽象产品)
- AbstractFactory (抽象工厂)
- Client (委托者)
具体实现如下,为了保证代码的阅读,这里不对类的具体操作进行展开
abstract class AbstractFactory {
abstract AbstractClass1 createClass1();
abstract AbstractClass2 createClass2();
abstract AbstractClass3 createClass3();
}
abstract class AbstractClass1 {}
abstract class AbstractClass2 {}
abstract class AbstractClass3 {}
class Class1 extends AbstractClass1{}
class Class2 extends AbstractClass2{}
class Class3 extends AbstractClass3{}
class Factory1 extends AbstractFactory{
@Override
AbstractClass1 createClass1() {
return new Class1();
}
@Override
AbstractClass2 createClass2() {
return new Class2();
}
@Override
AbstractClass3 createClass3() {
return new Class3();
}
}
class Factory2 extends AbstractFactory{
@Override
AbstractClass1 createClass1() {
return new Class1();
}
@Override
AbstractClass2 createClass2() {
return new Class2();
}
@Override
AbstractClass3 createClass3() {
return new Class3();
}
}
分析
从上面代码中,我们可以发现,抽象工厂处理的是产品一族,它们和工厂方法的区别在于:工厂方法有利于处理一个产品的部件扩展维度,而抽象工厂有利于扩展产品一族维度。
4、原型模式(Prototype)
特点:必须实现Cloneable接口,并且重写clone方法,否则会报错 应用场景:一个对象属性特别多,同时指定很麻烦,实际工作中用的很少
角色:
- Prototype(原型)
- ConcretePrototype(具体原型)
- Client(使用者)
浅克隆
//原型接口继承Cloneable接口,或者抽象类实现Cloneable接口
interface Prototype extends Cloneable{
}
//具体原型类实现原型接口,重写方法
public class ConcretePrototype implements Prototype {
@Override
protected Object clone() throws CloneNotSupportedException {
//通过克隆自身对象
ConcretePrototype p=(ConcretePrototype)this.clone();
//返回克隆后的值
return p;
}
}
通过clone实现深拷贝
//原型接口继承Cloneable接口,或者抽象类实现Cloneable接口
interface Prototype extends Cloneable{
}
//具体原型类实现原型接口,重写方法
public class ConcretePrototype implements Prototype {
//假设有一个对象属性,需要克隆这个对象属性
public Book book;
@Override
protected Object clone() throws CloneNotSupportedException {
//对基本属性进行克隆
Object deep=null;
deep=super.clone();
//对引用类型的数据进行单独处理
ConcretePrototype c=(ConcretePrototype )deep;
c.book= (Book)book.clone();
//返回克隆后的值
return deep;
}
}
缺点:繁琐 通过序列化实现深拷贝
public class Book implements Serializable{
public Object deepClone() {
ByteArrayInputStream bis=null;
ByteArrayOutputStream bos=null;
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try{
bos=new ByteArrayOutputStream();
oos=new ObjectOutputStream(bos);
oos.writeObject(this);
bis=new ByteArrayInputStream(bos.toByteArray());
ois=new ObjectInputStream(bis);
Book book=(Book)ois.readObject();
return book;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5、建造者模式(Builder)
特点:处理复杂对象的创建,在使用时只需要用想要的属性时,不需要设置所有参数;这个建造者模式和模板方法特别像
角色:
- Builder(建造者)
- ConcreteBuilder(具体建造者)
- Director(监工)
- Client(使用者)
interface Builder {
Builder creteBuilder();
Builder creteBuilder2();
Builder creteBuilder3();
}
class ConcreteBuilder implements Builder{
@Override
public Builder creteBuilder() {
System.out.println("建造第一层");
return this;
}
@Override
public Builder creteBuilder2() {
System.out.println("建造第二层");
return this;
}
@Override
public Builder creteBuilder3() {
System.out.println("建造第三层");
return this;
}
}
class Director {
Builder builder;
public Director(Builder builder) {
this.builder=builder;
}
public void toBuilder() {
builder.creteBuilder().creteBuilder2().creteBuilder3();
}
}
public class Client {
public static void main(String[] args) {
Director d=new Director(new ConcreteBuilder());
d.toBuilder();
}
}
比较常用的使用方式
public class Person {
int id;
String name;
int age;
double weight;
int score;
private Person() {}
public static class PersonBuilder{
Person p=new Person();
public PersonBuilder basicInfo(int id,String name,int age) {
p.id=id;
p.name=name;
p.age=age;
return this;
}
public PersonBuilder weight(double weight) {
p.weight=weight;
return this;
}
public PersonBuilder score(int score) {
p.score=score;
return this;
}
public Person build() {return p;}
}
public static void main(String[] args) {
Person p=new Person.PersonBuilder().basicInfo(1, "张三", 18).weight(65.0).build();
}
}
6、适配器模式(Adapte)
使不兼容的接口相融
角色:
- Target(对象)
- Adaptee(被适配)
- Adapter(适配)
1、类适配器模式
interface Target {
public int open110V();
}
class ClassAdaptee{
public int open220V(){
return 200;
}
}
public class ClassAdapte extends ClassAdapteeimplements Target{
@Override
public int open110V() {
int voltage=open220V();
return voltage/2;
}
}
2、对象适配器
和类适配器的区别,适配器和被适配者之间没有继承关系,通过聚合实现(合成复用)
abstract Target {
public abstract int open110V();
}
class ClassAdaptee{
public int open220V(){
return 200;
}
}
public class ClassAdapte extends Target{
public ClassAdaptee adaptee;
public ClassAdapte(ClassAdaptee e){
this.adaptee=e;
}
@Override
public int open110V() {
int voltage=e.open220V();
return voltage/2;
}
}
7、桥连模式(Bridge)了解
特点: 双维度扩展 分离抽象和具体 用聚合的方式连接抽象和具体
类图
abstract class AbstractBridge {
Implementor imt;
}
class ConcreteBride extends AbstractBridge{
public ConcreteBride(Implementor imt) {
this.imt=imt;
}
}
interface Implementor {
}
public class ConcreteImplementor implements Implementor{
}
8、装饰者模式(Decorator)
特点:对类进行扩展时不修改原有的代码,为类添加新的功能,防止类继承带来的爆炸性增长
类图:
案例应用:
abstract class Drink {
private String des;
private float price=0.0f;
public String getDes() {
return des+"价格:"+price;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
protected abstract float cost();
}
abstract class Coffee extends Drink{
}
class Cafe_Latte extends Coffee{
public Cafe_Latte() {
super.setDes("拿铁咖啡");
super.setPrice(18.80f);
}
@Override
protected float cost() {
return super.getPrice();
}
}
class Instant_Coffee extends Coffee{
public Instant_Coffee(int shuliang) {
super.setDes("速溶咖啡");
super.setPrice(14.00f);
}
@Override
protected float cost() {
return super.getPrice();
}
}
class Cafe_Latte extends Coffee{
public Cafe_Latte() {
super.setDes("拿铁咖啡");
super.setPrice(18.80f);
}
@Override
protected float cost() {
return super.getPrice();
}
}
class DeCorator extends Drink{
private Drink drink;
private String des;
private float price=0.0f;
private int shuliang=1;
public DeCorator(Drink drink) {
this.drink=drink;
}
public DeCorator(Drink drink,int shuliang) {
this.drink=drink;
this.shuliang=shuliang;
}
public String getDes() {
return drink.getDes()+" "+" 加入"+shuliang+"份"+des+" "+des+"单价:"+price;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
protected float cost() {
float material_price=this.price*this.shuliang;
return material_price+drink.cost();
}
}
class Milk extends DeCorator{
public Milk(Drink drink) {
super(drink);
super.setDes("牛奶");
super.setPrice(2f);
}
public Milk(Drink drink, int shuliang) {
super(drink, shuliang);
super.setDes("牛奶");
super.setPrice(2f);
}
}
class Sugar extends DeCorator{
public Sugar(Drink drink) {
super(drink);
super.setDes("糖");
super.setPrice(1f);
}
public Sugar(Drink drink, int shuliang) {
super(drink, shuliang);
super.setDes("糖");
super.setPrice(1f);
}
}
public class Client {
public static void main(String[] args) {
Drink order=new Cafe_Latte();
System.out.println("费用:"+order.cost());
System.out.println(order.getDes());
order=new Milk(order);
System.out.println("加入一份牛奶的费用:"+order.cost());
System.out.println(order.getDes());
}
}
9、享元模式(Flyweight)
特点:共享数据,重复利用对象
应用场景:数据库连接池
类图: 角色:
下面是图书馆案例,图书馆作为享元池,书架作为抽象化享元对象,书籍作为享元对象。
来看类图
abstract class Book {
HashMap<String,Boolean> start=new HashMap<>();
abstract void borrow(Lender lender);
abstract void setBookStart(String bookName,boolean bookStart);
abstract boolean getBookStart(String bookName);
}
class MixBook extends Book{
private String bookName="";
private boolean bookStart;
public MixBook(String bookName) {
this.bookName=bookName;
}
@Override
public void borrow(Lender lender) {
System.out.println(lender.getName()+"向图书馆借出一本"+bookName);
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public boolean getBookStart(String bookName) {
if(start.get(bookName)) return true;
else return false;
}
public void setBookStart(String bookName,boolean bookStart) {
start.put(bookName, bookStart);
}
}
class Lender {
private String name;
public Lender(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import java.util.HashMap;
class Library {
private static Library library=new Library();
private Library(){};
HashMap<String,Book> pool=new HashMap<>();
public static Library getInstance() {
return library;
}
public Book toBorrow(String bookName,Lender lender) {
Book book=null;
if(pool.isEmpty()) {
System.out.println("图书馆目前没有书,请添加书籍");
}
else if(!pool.containsKey(bookName)) {
System.out.println("图书馆没有"+bookName+",请联系图书管理员");
}else {
book=pool.get(bookName);
if(!book.getBookStart(bookName)){
System.out.println("你好"+lender.getName()+":"+bookName+"已经被借走了");
book=null;
}
else {
book.start.put(bookName, false);
book.borrow(lender);
}
}
return book;
}
public void shelveBook(String bookName,Book book) {
book.setBookStart(bookName,true);
pool.put(bookName, book);
}
public int poolSize() {
return pool.size();
}
}
public class Student {
public static void main(String[] args) {
Library library=Library.getInstance();
library.shelveBook("《Java编程思想》", new MixBook("《Java编程思想》"));
library.shelveBook("《Mysql必会知识》", new MixBook("《Mysql必会知识》"));
Lender lender=new Lender("小庄");
Book book1=library.toBorrow("《Java编程思想》",lender);
Book book2=library.toBorrow("《Java编程思想》",lender);
Book book3=library.toBorrow("《Mysql必会知识》",lender);
System.out.println("图书馆借出书籍共:"+library.poolSize()+"个");
}
}
10、代理模式(Proxy)
代理模式分为:静态代理,动态代理 本篇内容只对动态代理的jdk代理和cglib代理介绍
静态代理
角色:
interface IBoard {
void draw();
}
class Board implements IBoard{
@Override
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
class StaticProxy implements IBoard{
private IBoard board;
public StaticProxy(IBoard board) {
this.board=board;
}
@Override
public void draw() {
System.out.println("代理类执行自己操作");
System.out.print("============");
board.draw();
System.out.print("============");
System.out.println("代理类执行结束");
}
}
public class Client {
public static void main(String[] args) {
new StaticProxy(new Board()).draw();
}
}
动态代理模式之JDK代理
jdk代理主要通过反射的方式进行代理,JDK代理本身就继承了Proxy类,由于Java不支持多继承,所以不支持对类的代理,只支持对接口的代理。 具体案例如下:
interface IBoard {
void draw();
}
interface IComputer {
void open();
void complete();
}
class Board implements IBoard{
@Override
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
class Computer implements IComputer{
@Override
public void open() {
System.out.println("电脑正在启动....");
}
@Override
public void complete() {
System.out.println("电脑启动完成");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
class JDKProxy {
private Object target;
public JDKProxy(Object target) {
this.target=target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("=================");
System.out.println("代理开始");
Object object=method.invoke(target, args);
System.out.println("被代理的方法名:"+method.getName());
if("open"==method.getName()) {
Method complete=target.getClass().getMethod("complete");
if(null!=complete){
System.out.println("complete方法被代理对象自动调用");
Thread.sleep(1000);
complete.invoke(target, args);
}
}
System.out.println("代理结束");
System.out.println("=================");
System.out.println();
return object;
}
});
}
}
public class Client {
public static void main(String[] args) {
JDKProxy board=new JDKProxy(new Board());
IBoard iBoard=(IBoard)board.getProxyInstance();
iBoard.draw();
JDKProxy computer=new JDKProxy(new Computer());
IComputer iComputer=(IComputer) computer.getProxyInstance();
iComputer.open();
}
}
动态代理之cglib代理
我们知道,使用Jdk代理的不足之处是不能对类进行代理,而Cglib代理刚好解决了这个问题。 Cglib可以对无接口的类进行代理,需要实现MethodInterceptor接口
具体案例:
class Board{
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
class Computer{
public void open() {
System.out.println("电脑正在启动....");
}
public void complete() {
System.out.println("电脑启动完成");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class CglibProxy implements MethodInterceptor{
public Object target;
public CglibProxy(Object target) {
this.target=target;
}
public Object getProxyInstance() {
Enhancer e=new Enhancer();
e.setSuperclass(target.getClass());
e.setCallback(this);
return e.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("===============");
System.out.println("Cglib代理模式开始");
Object object=method.invoke(target, args);
System.out.println("被代理的方法名:"+method.getName());
if("open"==method.getName()) {
Method complete=target.getClass().getMethod("complete");
if(null!=complete){
System.out.println("complete方法被代理对象自动调用");
Thread.sleep(1000);
complete.invoke(target, args);
}
}
System.out.println("代理结束");
System.out.println("=================");
System.out.println();
return object;
}
}
11、组合模式(Composite)
一般适用于树状结构的场景,比如文件结构,比如层级结构
实现代码如下:
abstract class Node {
public abstract void printNode();
}
import java.util.ArrayList;
import java.util.List;
class BranchNode extends Node{
String nodeName;
public List<Node> nodes=new ArrayList<>();
public BranchNode(String nodeName) {
this.nodeName=nodeName;
}
public void addNode(Node node) {
nodes.add(node);
}
@Override
public void printNode() {
System.out.println(nodeName);
}
}
class LeafNode extends Node{
String nodeName;
public LeafNode(String nodeName) {
this.nodeName=nodeName;
}
@Override
public void printNode() {
System.out.println(nodeName);
}
}
public class Client {
public static void main(String[] args) {
BranchNode root=new BranchNode("根结点");
BranchNode node1=new BranchNode("结点1");
Node c1=new LeafNode("叶子结点1");
Node c2=new LeafNode("叶子结点2");
root.addNode(node1);
node1.addNode(c1);
node1.addNode(c2);
tree(root,0);
}
public static void tree(Node node,int depth) {
for(int i=0;i<depth;i++) {
System.out.print("--");
}
node.printNode();
if(node instanceof BranchNode) {
for(Node n:((BranchNode) node).nodes){
tree(n,depth+1);
}
}
}
}
生活中用到组合模式的例子:学校,学院(系)和专业
abstract class Composite {
private String des;
private String name;
public Composite(String name,String des) {
this.name=name;
this.des=des;
}
protected void add(Composite composite) {
}
protected void remove(Composite composite) {}
protected abstract void print();
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.HashSet;
class College extends Composite{
HashSet<Major> majors=new HashSet<>();
public College(String name,String des) {
super(name,des);
}
@Override
protected void add(Composite composite) {
majors.add((Major)composite);
}
@Override
protected void remove(Composite composite) {
majors.remove((Major)composite);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("学院:"+getName());
System.out.println();
for(Major major:majors) {
System.out.println("专业:"+major.getName()+"\t专业详情:"+major.getDes());
}
System.out.println("=====================");
}
}
import java.util.Set;
class University extends Composite{
Set<College> colleges=new HashSet<>();
public University(String name,String des) {
super(name,des);
}
@Override
protected void add(Composite composite) {
colleges.add((College)composite);
}
@Override
protected void remove(Composite composite) {
colleges.remove((College)composite);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("========"+getName()+"========");
System.out.println("简介:"+getDes());
System.out.println();
for(College college:colleges) {
System.out.println("学院:"+college.getName()+"\t学院详情:"+college.getDes());
}
System.out.println("=====================");
}
}
public class Major extends Composite{
public Major(String name,String des) {
super(name,des);
}
@Override
protected void print() {
System.out.println(super.getName()+super.getDes());
}
}
public class Client {
public static void main(String[] args) {
University university=new University("清华大学", "中国顶尖学府");
College c=new College("计算机学院","培养软件+硬件高级人才");
university.add(c);
university.add(new College("金融学院", "培养金融行业高级人才"));
university.print();
c.add(new Major("计算机科学与技术","老牌的计算机专业"));
c.print();
}
}
12、外观模式(Facade)
外观模式又称为门面模式,通常和责任链模式结合使用 使用场景:解决多个类之间的复杂关系,只需要通过一个类就可以直接和其他类进行交互,具体使用:中间件
通过案例进行讲解:
class Agent {
private static Agent agent=new Agent();
protected Star star=Star.getInstance();;
protected Fans fans=Fans.getInstance();
protected Company company=Company.getInstance();
private Agent() {}
protected void meeting() {
System.out.println("粉丝"+fans.getName()+"与"+star.getName()+"获得一次见面机会");
}
protected void contract() {
System.out.println("明星"+star.getName()+"与"+company.getName()+"进行了签约");
}
public static Agent getInstance() {
return agent;
}
}
class Star {
private static Star star=new Star();
protected volatile String name="";
private Star() {}
public String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
protected static Star getInstance() {
return star;
}
}
class Fans {
private static Fans fans=new Fans();
private volatile String name="";
private Fans() {}
public String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
public static Fans getInstance() {
return fans;
}
}
class Company {
private volatile String name="";
private static Company company=new Company();
private Company() {}
public String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
public static Company getInstance() {
return company;
}
}
public class Client {
public static void main(String[] args) {
Agent agent=Agent.getInstance();
agent.company.setName("公司x");
agent.fans.setName("张三");
agent.star.setName("吴签");
agent.meeting();
agent.contract();
System.out.println("============");
agent.fans.setName("李四");
agent.meeting();
agent.contract();
}
}
我们可以看到,经纪人就是一个门面,其他人都是通过经纪人来处理事情。粉丝想要见明星,首先要通过经纪人。再由经纪人和明星打交道。
13、状态模式(State)
如果一个类有很多个复杂状态的时候,可以把状态抽象出来,具体状态实现这个抽象类,
角色:
- State(状态)
- ConcreteState(具体状态)
- Context(状况)
abstract class State {
public abstract void simle();
public abstract void cry();
}
class HappyState extends State{
@Override
public void simle() {
System.out.println("开心的笑");
}
@Override
public void cry() {
System.out.println("开心的哭了");
}
}
class SadState extends State{
@Override
public void simle() {
System.out.println("沮丧的笑着");
}
@Override
public void cry() {
System.out.println("笑哭了");
}
}
public class Context{
private State state;
public Context(State state) {
this.state=state;
}
public void simle() {
state.simle();
}
public void cry() {
state.cry();
}
}
我们不难发现,抽象类的状态(抽象方法)是固定的,具体是怎样的状态,由子类实现。如果抽象类的状态(抽象方法)变化的很频繁,会对所有子类产生影响,那么就不建议使用这个模式
14、责任链模式(Responsibility)
是一种链式的结构的模式,通常使用在审批流,过滤器
abstract class Approve {
private Approve approve;
public void setApprove(Approve approve) {
this.approve=approve;
}
public abstract void toApprove();
public abstract void chain(Approve approve);
}
class Approve1 extends Approve{
@Override
public void toApprove() {
System.out.println("我是审批人1,我审批完之后交给审批人2");
chain(new Approve2());
}
@Override
public void chain(Approve approve) {
approve.toApprove();
}
}
class Approve2 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人2,我审批完之后交给审批人3");
chain(new Approve3());
}
@Override
public void chain(Approve approve) {
approve.toApprove();
}
}
class Approve3 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人3,审批完成");
}
@Override
public void chain(Approve approve) {
approve.toApprove();
}
}
public class Request {
public static void main(String[] args) {
Approve approve=new Approve1();
approve.toApprove();
}
}
换一种思路,我们把每一个子类存到容器中,然后对容器进行遍历,然后执行方法,也类似这种链式的执行流程。 我们来通过代码来看看
abstract class Approve {
public abstract void toApprove();
}
class Approve1 extends Approve{
@Override
public void toApprove() {
System.out.println("我是审批人1,我审批完之后交给审批人2");
}
}
class Approve2 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人2,我审批完之后交给审批人3");
}
}
class Approve3 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人3,审批完成");
}
}
import java.util.ArrayList;
class ApproveChain {
ArrayList<Approve> approves=new ArrayList<>();
public ApproveChain addChain(Approve approve) {
approves.add(approve);
return this;
}
public void chain() {
for(Approve a:approves) {
a.toApprove();
}
}
}
public class Request {
public static void main(String[] args) {
ApproveChain ac=new ApproveChain();
ac.addChain(new Approve1()).addChain(new Approve2()).addChain(new Approve3());
ac.chain();
}
}
上面代码很类似享元模式吧,哈哈。
15、迭代器模式(Iterator)
角色:
- Iterator(迭代器)
- ConcreteIterator(具体的迭代器)
- Aggregate(集合)
- CocreteAggreagete(具体集合)
类图: Iterator(迭代器)
public interface Iterator_ {
boolean hashNext();
Object next();
}
ConcreteIterator(具体的迭代器)
public class ArrayListIterator implements Iterator_{
private static ArrayListAggregate alat=new ArrayListAggregate();
@Override
public boolean hashNext() {
if(alat.currentIndex>=alat.size()) return true;
return false;
}
@Override
public Object next() {
Object o=alat.list.get(alat.currentIndex);
alat.currentIndex++;
return o;
}
}
Aggregate(集合接口)
public interface Aggregate {
public abstract Iterator_ iterator();
}
CocreteAggreagete(具体集合)
import java.util.ArrayList;
public class ArrayListAggregate implements Aggregate{
ArrayList<Object> list=new ArrayList<>();
int index=0;
int currentIndex=0;
@Override
public Iterator_ iterator() {
return new ArrayListIterator();
}
public int size() {
return index;
}
public void add(Object o) {
list.add(o);
index++;
}
}
16、观察者模式(Observer)重要
我们开发中,使用到观察者模式很多,这个知识点要重点把握
通知对象状态改变,允许一个对象向所有侦听对象广播自己的消息或事件
角色:
- Source:事件源对象
- Observer:观察者
- Event:事件
class Event {
String loc;
public Event(String loc) {
this.loc=loc;
}
}
abstract class Observer {
public abstract void actionEvent(Event event);
}
class Observer1 extends Observer{
@Override
public void actionEvent(Event event) {
System.out.println(event.loc);
System.out.println("观察者1做出了行为");
}
}
class Observer2 extends Observer{
@Override
public void actionEvent(Event event) {
System.out.println("============");
System.out.println("观察者2做出了行为");
}
}
import java.util.ArrayList;
import java.util.List;
public class Source {
private List<Observer> observers=new ArrayList<>();
{
observers.add(new Observer1());
observers.add(new Observer2());
}
public void wakeUp() {
for(Observer o:observers) {
o.actionEvent(new Event("bed"));
}
}
}
class Test {
public static void main(String[] args) {
new Source().wakeUp();
}
}
17、策略模式(Strategy)
角色:
封装的是不同的执行方式,比如对排序选择不同的排序算法(策略) 代码如下
interface Sorter{
public abstract void sort(Comparable[] data);
}
class SelectSorter implements Sorter{
@Override
public void sort(Comparable[] data) {
for(int i=0;i<data.length-1;i++) {
int min=i;
for(int j=i+1;j<data.length;j++) {
if(data[min].compareTo(data[j])>0) {
min=j;
}
}
swap(data,i,min);
}
}
public void swap(Comparable[] data,int i,int min) {
Comparable temp=data[i];
data[i]=data[min];
data[min]=temp;
}
}
class BubbleSorter implements Sorter{
@Override
public void sort(Comparable[] data) {
for(int i=1;i<data.length;i++) {
for(int j=0;j<data.length-i;j++) {
if(data[j].compareTo(data[j+1])>0) {
Comparable temp=data[j+1];
data[j+1]=data[j];
data[j]=temp;
}
}
}
}
}
class SortAndPrint{
Comparable[] data;
Sorter sorter;
public SortAndPrint(Comparable[] data,Sorter sorter) {
this.data=data;
this.sorter=sorter;
}
public void sort() {
System.out.println("====排序前====");
print();
sorter.sort(data);
System.out.println();
System.out.println("====排序后====");
print();
}
public void print() {
for(int i=0;i<data.length;i++) {
System.out.print(data[i]+",");
}
System.out.println(" ");
}
}
public class Client {
public static void main(String[] args) {
String[] data= {"Dumpty","Bowman","Carroll"};
SortAndPrint sap=new SortAndPrint(data, new BubbleSorter());
sap.sort();
}
}
18、模板方法模式(Temlapte Method)
具体实现交给子类 角色:
- AbstractClass
- concreteClass
类图:
具体使用:
public abstract class AbstractDisplay {
public abstract void open();
public abstract void print();
public abstract void close();
public final void display() {
open();
print();
close();
}
public static void main(String[] args){
CharDisplay chars=new CharDisplay();
chars.display();
}
}
class CharDisplay extends AbstractDisplay{
@Override
public void open() {
System.out.println("打开CharDisplay");
}
@Override
public void print() {
System.out.println("在CharDisplay进行打印");
}
@Override
public void close() {
System.out.println("关闭CharDisplay");
}
}
class StringDisplay extends AbstractDisplay{
@Override
public void open() {
System.out.println("打开StringDisplay");
}
@Override
public void print() {
System.out.println("在StringDisplay进行打印");
}
@Override
public void close() {
System.out.println("关闭StringDisplay");
}
public void printLine() {
System.out.println("StringDisplay自定义的方法");
}
}
应用场景:
- 算法的整体步骤很固定,但其中个别部分易变,将易变部分交给子类实现。
- 多个子类存在公共行为,可以将其提取出并集中到一个公共父类以避免代码重复
- 需要控制子类的扩展时,模板方法只在特定点调用钩子函数操作,这样就只允许在这些点进行扩展。
19、中介者模式(Mediator)
中介这个角色在生活中的理解是:比如租房者找中介,再由中介跟相关的房东沟通,房东也是通过中介和租房者沟通。中介是中间的桥梁。 在中介者模式中的理解和生活中的理解基本一致
角色:
- Mediator 抽象化中介者
- ConcentrateMediator 具体中介者
- College 抽象化同事类
- ConcentrateCollege 具体同事类(租房者、房东)
pabstract class Mediator {
public abstract void constact(String msg,Colleague c);
}
class ConcreteMediator extends Mediator{
private ConcreteColleague1 c1;
private ConcreteColleague2 c2;
public ConcreteColleague1 getC1() {
return c1;
}
public void setC1(ConcreteColleague1 c1) {
this.c1 = c1;
}
public ConcreteColleague2 getC2() {
return c2;
}
public void setC2(ConcreteColleague2 c2) {
this.c2 = c2;
}
@Override
public void constact(String msg, Colleague c) {
if(c==c1) {
c2.getMessage(msg);
}else {
c1.getMessage(msg);
}
}
}
abstract class Colleague {
protected String name;
protected Mediator mediator;
public Colleague(String name,Mediator mediator) {
this.name=name;
this.mediator=mediator;
}
public abstract void constact(String msg);
public abstract void getMessage(String msg);
}
class ConcreteColleague1 extends Colleague{
public ConcreteColleague1(String name,Mediator mediator) {
super(name, mediator);
}
@Override
public void constact(String msg) {
mediator.constact(msg, this);
}
@Override
public void getMessage(String msg) {
System.out.println();
System.out.println("租房者姓名:"+name+"。收到的信息:"+msg);
}
}
class ConcreteColleague2 extends Colleague{
public ConcreteColleague2(String name,Mediator mediator) {
super(name,mediator);
}
@Override
public void constact(String msg) {
mediator.constact(msg, this);
}
@Override
public void getMessage(String msg) {
System.out.println("房东姓名:"+name+"。收到的信息:"+msg);
}
}
public class Client {
public static void main(String[] args) {
ConcreteMediator cm=new ConcreteMediator();
ConcreteColleague1 c1=new ConcreteColleague1("张三",cm);
ConcreteColleague2 c2=new ConcreteColleague2("李四",cm);
cm.setC1(c1);
cm.setC2(c2);
c1.constact("我想租两房一厅的房子");
c2.constact("我这有,而且非常便宜");
}
}
20、备忘录模式(Memento)
记录状态,便于回滚,经常和命令模式结合使用 角色:
- Memento 备忘录,记录状态
- Originator 创建者:创建备忘录
- Caretaker 管理者:管理备忘录
class Memento {
private String state;
public Memento(String state) {
this.state=state;
}
public String getState() {
return state;
}
}
class Originator {
private String state;
public void setState(String state) {
this.state=state;
System.out.println("现在的状态为:"+state);
}
public String getState() {
return state;
}
public Memento saveMemento() {
return new Memento(state);
}
public void getStateFromMemento(Memento memento) {
this.state=memento.getState();
}
}
import java.util.ArrayList;
class Caretaker {
private ArrayList<Memento> mementos=new ArrayList<>();
public void addMemento(Memento memento) {
mementos.add(memento);
}
public Memento getMemento(int index) {
return mementos.get(index);
}
}
public class Client {
public static void main(String[] args) {
Originator o=new Originator();
Caretaker c=new Caretaker();
o.setState("状态1:攻击力:1000");
c.addMemento(o.saveMemento());
o.setState("状态2:攻击力:800");
c.addMemento(o.saveMemento());
String state=c.getMemento(0).getState();
System.out.println("恢复后的状态为:"+state);
}
}
备忘录模式能够随时恢复到备忘录保存的状态,而命令模式需要多个撤销恢复上一个状态。备忘录模也会用在存盘功能,将会使用到序列化和反序化,对于序列化和反序列化的相关使用可以查看这里:
序列化和反序列化的相关知识
可以尝试实现这个功能,这里就不展开介绍了。
21、命令模式(Command)
需要回退(撤销,Undo)状态的时候通常会使用到命令模式 多次撤销,需要结合责任链模式 宏命令,需要树状结构的组合模式结合使用
命令的调用者和命令的接收者进行了解耦
角色:
- invok 调用者
- Command 命令
- Receive 接收者
下面代码是对单个命令的执行和撤销作用
interface Command {
void execute();
void undo();
}
class Command1 implements Command{
private Receive receive;
String str="https://blog.csdn.net/weixin_44715643?spm=1000.2115.3001.5343";
public Command1(Receive receive) {
this.receive=receive;
}
@Override
public void execute() {
System.out.println("接收者的内容:"+receive.msg);
receive.msg+=str;
System.out.println("接收者的内容发生了改变:"+receive.msg);
}
@Override
public void undo() {
receive.msg=receive.msg.substring(0, receive.msg.length()-str.length());
System.out.println("恢复回上一步的操作时的接收者的内容:"+receive.msg);
}
}
class Receive {
String msg=new String("hello everybody ");
}
class Invok {
private Command command;
public Invok(Command command) {
this.command=command;
}
public void executeCommand() {
command.execute();
}
public void undoCommand() {
command.undo();
}
}
public class Client {
public static void main(String[] args) {
Invok invok=new Invok(new Command1(new Receive()));
invok.executeCommand();
System.out.println("下面进行撤销操作");
invok.undoCommand();
}
}
多个命令的执行和撤销
abstract class Command {
abstract int getIndex();
abstract void execute();
abstract Command undo();
}
import java.util.ArrayList;
class Command1 extends Command{
private ArrayList<String> alist=new ArrayList<>();
private int index=-1;
private Receive receive;
String str="xxx ";
public Command1(Receive receive) {
this.receive=receive;
}
@Override
public void execute() {
System.out.println("接收者的内容:"+receive.msg);
receive.msg+=str;
System.out.println("接收者的内容发生了改变:"+receive.msg);
alist.add(receive.msg);
index++;
}
@Override
public Command1 undo() {
if(index>=0) {
if(index==0) {
receive.msg=receive.msg.substring(0,receive.chushizhi.length());
alist.remove(index);
index--;
System.out.println("初始值为:"+receive.msg);
}else {
alist.remove(index);
String s=alist.get(--index);
receive.msg=receive.msg.substring(0, s.length());
System.out.println("恢复回上一步的操作时的接收者的内容:"+receive.msg);
}
}else {
System.out.println("到底了,不能再撤销了");
}
return this;
}
@Override
public int getIndex() {
return index;
}
}
class Receive {
String msg="hello everybody ";
String chushizhi=msg;
}
class Invok {
private Command command;
public Invok(Command command) {
this.command=command;
}
public void executeCommand() {
command.execute();
}
public Invok undoCommand() {
command.undo();
return this;
}
}
public class Client {
public static void main(String[] args) {
Invok invok=new Invok(new Command1(new Receive()));
invok.executeCommand();
invok.executeCommand();
invok.executeCommand();
System.out.println("下面进行撤销操作");
invok.undoCommand();
invok.undoCommand();
invok.undoCommand();
invok.undoCommand();
}
}
22、访问者模式(Visitor)
数据结构和数据分离
角色:
- Visitor 访问者抽象类 - Element 具体元素
- Struct 结构,由多个元素组成
- 具体元素
interface Visitor {
void visitCpu(Cpu cpu);
void visitMemory(Memory memory);
void visitBoard(Board board);
}
class Woman implements Visitor{
double totalPrice=0.0;
@Override
public void visitCpu(Cpu cpu) {
totalPrice+=cpu.getPrice()*0.75;
}
@Override
public void visitMemory(Memory memory) {
totalPrice+=memory.getPrice()*0.75;
}
@Override
public void visitBoard(Board board) {
totalPrice+=board.getPrice()*0.75;
}
public double getPrice() {
return totalPrice;
}
}
class Man implements Visitor{
double totalPrice=0.0;
@Override
public void visitCpu(Cpu cpu) {
totalPrice+=cpu.getPrice()*0.8;
}
@Override
public void visitMemory(Memory memory) {
totalPrice+=memory.getPrice()*0.8;
}
@Override
public void visitBoard(Board board) {
totalPrice+=board.getPrice()*0.8;
}
public double getPrice() {
return totalPrice;
}
}
interface ComputerPart {
void accept(Visitor visitor);
}
class Board implements ComputerPart{
@Override
public void accept(Visitor visitor) {
visitor.visitBoard(this);
}
public double getPrice() {
return 1000.00;
}
}
class Cpu implements ComputerPart{
@Override
public void accept(Visitor visitor) {
visitor.visitCpu(this);
}
public double getPrice() {
return 800.0;
}
}
class Memory implements ComputerPart{
@Override
public void accept(Visitor visitor) {
visitor.visitMemory(this);
}
public double getPrice() {
return 400.00;
}
}
public class Computer {
Cpu cpu=new Cpu();
Memory memory=new Memory();
Board board=new Board();
public void accept(Visitor visitor) {
this.cpu.accept(visitor);
this.memory.accept(visitor);
this.board.accept(visitor);
}
}
public class Test {
public static void main(String[] args) {
Computer computer=new Computer();
Man man=new Man();
Woman woman=new Woman();
computer.accept(man);
System.out.println("男人过来买需要花费:"+man.getPrice());
computer.accept(woman);
System.out.println("女人过来买需要花费:"+woman.getPrice());
}
}
23、解释器模式(Interpreter)
对于一些固定文法构建一个解释句子的解释器。在实际开发中,我们很少会去开发一个解释器,因为涉及到的知识点比较复杂。所以我们只需要了解即可,我们通过加减法的例子去了解它
角色:
- Expression 抽象化解释器
- Context 上下文,用于存放变量和值
- Addition 加法解释器(具体解释器)
- Minus 减法解释器(具体解释器)
- Variable 变量解释器 (具体解释器),它主要和上下文打交道(获取变量指定的值)
abstract class Expression {
public abstract int interpret(Context context);
}
import java.util.HashMap;
class Context {
private HashMap<Variable,Integer> map=new HashMap<>();
public void addVariable(Variable v,Integer x) {
map.put(v, x);
}
public int getVlaue(Variable v) {
return map.get(v);
}
}
class Variable extends Expression{
String name;
public Variable(String name) {
this.name=name;
}
@Override
public int interpret(Context context) {
return context.getVlaue(this);
}
@Override
public String toString() {
return name;
}
}
class Addition extends Expression{
private Expression left;
private Expression right;
public Addition(Expression left,Expression right) {
this.left=left;
this.right=right;
}
@Override
public int interpret(Context context) {
return left.interpret(context)+right.interpret(context);
}
@Override
public String toString() {
return "("+left.toString()+"+"+right.toString()+")";
}
}
class Minus extends Expression{
private Expression left;
private Expression right;
public Minus(Expression left,Expression right) {
this.left=left;
this.right=right;
}
@Override
public int interpret(Context context) {
return left.interpret(context)-right.interpret(context);
}
@Override
public String toString() {
return "("+left.toString()+"-"+right.toString()+")";
}
}
public class Client {
public static void main(String[] args) {
Context context=new Context();
Variable a=new Variable("a");
Variable b=new Variable("b");
Variable c=new Variable("c");
Variable d=new Variable("d");
context.addVariable(a, 1);
context.addVariable(b, 2);
context.addVariable(c, 3);
context.addVariable(d, 4);
Expression expression=new Addition(a,new Minus(b,new Addition(c,d)));
int result=expression.interpret(context);
System.out.println(expression.toString()+"="+result);
}
}
结语
通过上面的学习,我们发现很多设计模式都十分相似,其实这很正常,因为这些设计模式都是基于Java的继承、多态、聚合、组合等方式完成的。我们应该学习这些模式的设计思想,它们适合在什么场景,并且我们不需要归根到底是哪个设计模式,只要我们类的设计的合理,达到我们的需求即可。通过学习这个知识点,我们能够更加深入的理解开发框架的底层设计原理,有助于我们后面的学习。 我是小庄,欢迎大家和我一起成长。
|