设计模式六大原则(SOLID)
- 单一职责原则(Single Responsibility Principle):对一个类而言,应该仅有一个引起它变化的原因。
- 开闭原则(Open-Close Principle):对扩展开放、对修改关闭。
- 里氏替换原则(Liskov Substitution Principle):凡是父类出现的地方,都可以用子类替换
- 迪米特法则(Law of Demeter):最少知道原则,一个类应该对需要耦合或调用的类知道的最少
- 接口隔离原则(Interface Segregation Principle):接口尽量细化,同时保证接口中的方法尽量的少。
- 依赖倒置(Dependence Inversion Principle):高层模块不应该依赖底层实现模块,应该依赖其抽象,面向接口编程。
设计模式分类
1994年,GOF(四人帮,全拼 Gang of Four)总结推出了23种设计模式,可分为三大类(创建型、结构型、行为型)
模式 & 描述 | 包括 |
创建型模式 创建对象同时隐藏构造方法,提供了创建对象的方式,而不是直接使用new |
|
结构型模式 关注类和对象的组合,使得类或对象获得新的功能。 |
|
行为型模式 关注对象之间的通信。 |
|
模式详解
创建型模式
单例模式
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
//单例模式通用代码
public class Singleton {
private static final Singleton singleton = new Singleton(); //限制产生多个对象
private Singleton(){} //通过该方法获得实例对象
public static Singleton getSingleton(){
return singleton;
}
// 类中其他方法,尽量是static
public static void doSomething(){}
}
工厂模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
//产品抽象类
public abstract class Product {
public void method1(){
//业务逻辑处理
}
//抽象方法
public abstract void method2();
}
//产品类1
public class ConcreteProduct1 extends Product {
public void method2() {
//业务逻辑处理
}
}
//产品类2
public class ConcreteProduct2 extends Product {
public void method2() {
//业务逻辑处理
}
}
//工厂抽象类
public abstract class Creator {
public abstract <T extends Product> T createProduct(Class<T> c);
}
//具体工厂类
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
}
抽象工厂模式
为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。
//抽象产品类
public abstract class AbstractProductA {
//每个产品共有的方法
public void shareMethod(){ }
//每个产品相同方法,不同实现
public abstract void doSomething();
}
//产品A1的实现类
public class ProductA1 extends AbstractProductA {
public void doSomething() {
System.out.println("产品A1的实现方法");
}
}
//产品A2的实现类
public class ProductA2 extends AbstractProductA {
public void doSomething() {
System.out.println("产品A2的实现方法");
}
}
//产品B与此类似,不再赘述....
//抽象工厂类
public abstract class AbstractCreator {
//创建A产品家族
public abstract AbstractProductA createProductA();
//创建B产品家族
public abstract AbstractProductB createProductB();
} //注意 有N个产品族,在抽象工厂类中就应该有N个创建方法。
//产品等级1的实现类
public class Creator1 extends AbstractCreator {
//只生产产品等级为1的A产品
public AbstractProductA createProductA() {
return new ProductA1();
}
//只生产产品等级为1的B产品
public AbstractProductB createProductB() {
return new ProductB1();
}
}
//产品等级2的实现类
public class Creator2 extends AbstractCreator {
//只生产产品等级为2的A产品
public AbstractProductA createProductA() {
return new ProductA2();
}
//只生产产品等级为2的B产品
public AbstractProductB createProductB() {
return new ProductB2();
}
}
//注意有M个产品等级就应该有M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。
//场景类
public class Client {
public static void main(String[] args) {
//定义出两个工厂
AbstractCreator creator1 = new Creator1();
AbstractCreator creator2 = new Creator2();
//产生A1对象
AbstractProductA a1 = creator1.createProductA();
//产生A2对象
AbstractProductA a2 = creator2.createProductA();
//产生B1对象
AbstractProductB b1 = creator1.createProductB();
//产生B2对象
AbstractProductB b2 = creator2.createProductB();
/* * 然后在这里就可以为所欲为了... */
}
}
建造者模式
建造者模式(Builder Pattern)也叫做生成器模式,其定义如下:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
//产品类
public class Product {
public void doSomething(){
//独立业务处理
}
}
//抽象建造者
public abstract class Builder {
//设置产品的不同部分,以获得不同的产品
public abstract void setPart();
//建造产品
public abstract Product buildProduct();
}
//具体建造者
public class ConcreteProduct extends Builder {
private Product product = new Product(); //设置产品零件
public void setPart(){
/*
* 产品类内的逻辑处理
*/
}
//组建一个产品
public Product buildProduct() {
return product;
}
}
//导演类
public class Director {
private Builder builder = new ConcreteProduct();
//构建不同的产品
public Product getAProduct(){
builder.setPart();
/*
* 设置不同的零件,产生不同的产品
*/
return builder.buildProduct();
}
}
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式的核心是一个clone方法,通过该方法进行对象的拷贝。
//原型模式通用源码
public class PrototypeClass implements Cloneable{
//覆写父类Object方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
//异常处理
}
return prototypeClass;
}
}
结构型模式
适配器模式
将一个类的接口变换成客户端期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
/*
*目标角色是一个已经在正式运行的角色,你不可能去修改角色中的方法,你能做的就是
*如何去实现接口中的方法,而且通常情况下,目标角色是一个接口或者是抽象类,一般不会 是实现类。一个正
*在服役的目标角色
*/
//目标角色
public interface Target {
//目标角色有自己的方法
public void request();
}
// 目标角色的实现类
public class ConcreteTarget implements Target {
public void request() {
System.out.println("if you need any help,pls call me!");
}
}
/*
*源角色也是已经在服役状态(当然,非要新建立一个源角色,然后套用适配器模式,那
*也没有任何问题),它是一个正常的类
*/
//源角色
public class Adaptee {
//原有的业务逻辑
public void doSomething(){
System.out.println("I'm kind of busy,leave me alone,pls!");
}
}
//适配器角色
public class Adapter extends Adaptee implements Target {
public void request() {
super.doSomething();
}
}
//场景类
public class Client {
public static void main(String[] args) {
//原有的业务逻辑
Target target = new ConcreteTarget();
target.request();
//现在增加了适配器角色后的业务逻辑
Target target2 = new Adapter();
target2.request();
}
}
桥接模式
将抽象和实现解耦,使得两者可以独立地变化。桥梁模式的重点是在“解耦”上。
桥梁模式中的4个角色。
● Abstraction——抽象化角色,定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类。
● Implementor——实现化角色,接口或者抽象类,定义角色必需的行为和属性。
● RefinedAbstraction——修正抽象化角色,引用实现化角色对抽象化角色进行修正。
● ConcreteImplementor——具体实现化角色,实现接口或抽象类定义的方法和属性。
抽象角色引用实现角色,或者说抽象角色的部分实现是由实现角色完成的
//实现化角色(它没有任何特殊的地方,就是一个一般的接口,定义要实现的方法)
public interface Implementor {
//基本方法
public void doSomething();
public void doAnything();
}
//具体实现化角色1
public class ConcreteImplementor1 implements Implementor{
public void doSomething(){
//业务逻辑处理
}
public void doAnything(){
//业务逻辑处理
}
}
//具体实现化角色2
public class ConcreteImplementor2 implements Implementor{
public void doSomething(){
//业务逻辑处理
}
public void doAnything(){
//业务逻辑处理
}
}
//抽象化角色
public abstract class Abstraction {
//定义对实现化角色的引用
private Implementor imp;
//约束子类必须实现该构造函数
public Abstraction(Implementor _imp){
this.imp = _imp;
}
//自身的行为和属性
public void request(){
this.imp.doSomething();
}
//获得实现化角色
public Implementor getImp(){
return imp;
}
}
//具体抽象化角色
public class RefinedAbstraction extends Abstraction {
//覆写构造函数
public RefinedAbstraction(Implementor _imp){
super(_imp);
}
//修正父类的行为
@Override
public void request(){
/*
* 业务处理...
*/
super.request();
super.getImp().doAnything();
}
}
//场景类
public class Client {
public static void main(String[] args) {
//定义一个实现化角色
Implementor imp = new ConcreteImplementor1();
//定义一个抽象化角色
Abstraction abs = new RefinedAbstraction(imp);
//执行行文
abs.request();
}
}
组合模式
组合模式(Composite Pattern)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系。
定义如下:将对象组合成树形结构以表 示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
- Component抽象构件角色:定义参加组合对象的共有方法和属性,定义一些默认的行为或属性
- Leaf叶子构件:叶子对象,其下再也没有其他的分支,也就是遍历的最小单位。
Composite树枝构件:树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构。
//抽象构件
public abstract class Component {
//个体和整体都具有的共享
public void doSomething(){
//编写业务逻辑
}
}
//树枝构件
public class Composite extends Component {
//构件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>()
//增加一个叶子构件或树枝构件
public void add(Component component){
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
public ArrayList<Component> getChildren(){
return this.componentArrayList;
}
}
//树叶构件
public class Leaf extends Component {
/*
* 可以覆写父类方法
* public void doSomething(){
*
* }
*/
}
// 场景类
public class Client {
public static void main(String[] args) {
//创建一个根节点
Composite root = new Composite();
root.doSomething();
//创建一个树枝构件
Composite branch = new Composite();
//创建一个叶子节点
Leaf leaf = new Leaf();
//建立整体
root.add(branch);
branch.add(leaf);
}
//通过递归遍历树
public static void display(Composite root){
for(Component c:root.getChildren()){
if(c instanceof Leaf){ //叶子节点
c.doSomething();
}else{ //树枝节点
display((Composite)c);
}
}
}
}
装饰器模式
动态地给一个对象添加一些额外的职责。
● Component:抽象构件,一个接口或者是抽象类,定义最核心的对象,也就是最原始的对象
● ConcreteComponent :具体构件,是最核心、最原始、最基本的接口或抽象类的实现,要装饰的就是它。
● Decorator:装饰角色,一般是一个抽象类,在它的属性里必然有一个private变量指向Component抽象构件。
● ConcreteDecorator:具体的装饰类,把最核心的、最原始的、最基本的东西装饰成其他东西
//抽象构件
public abstract class Component {
//抽象的方法
public abstract void operate();
}
//具体构件
public class ConcreteComponent extends Component {
//具体实现
@Override
public void operate() {
System.out.println("do Something");
}
}
//抽象装饰者
public abstract class Decorator extends Component {
private Component component = null;
//通过构造函数传递被修饰者
public Decorator(Component _component){
this.component = _component;
}
//委托给被修饰者执行
@Override
public void operate() {
this.component.operate();
}
}
//若只有一个装饰类,则可以没有抽象装饰角色,直接实现具体的装饰角色即可。
//代码清单17-13 具体的装饰类
public class ConcreteDecorator1 extends Decorator {
//定义被修饰者
public ConcreteDecorator1(Component _component){
super(_component);
}
//定义自己的修饰方法
private void method1(){
System.out.println("method1 修饰");
}
//重写父类的Operation方法
public void operate(){
this.method1();
super.operate();
}
}
public class ConcreteDecorator2 extends Decorator {
//定义被修饰者
public ConcreteDecorator2(Component _component){
super(_component);
}
//定义自己的修饰方法
private void method2(){
System.out.println("method2修饰");
}
//重写父类的Operation方法
public void operate(){
super.operate();
this.method2();
}
}
//原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。
//场景类
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
//第一次修饰
component = new ConcreteDecorator1(component);
//第二次修饰
component = new ConcreteDecorator2(component);
//修饰后运行
component.operate();
}
}
外观模式
门面模式也叫做外观模式,是一种比较常用的封装模式。
定义:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。
门面模式注重“统一的对象”,也就是提供一个访问子系统的接口,除了这个接口不允许 有任何访问子系统的行为发生。
简单地说,门面对象是外界访问子系统内部的唯一通道,不管子系统内部是多么杂乱 无章,只要有门面对象在,就可以做到“金玉其外,败絮其中”。
● Facade:门面角色,客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。一般情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就说该角色没有实际的业务逻辑,只是一个委托类。
● Subsystem:子系统角色,可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户端而已。
public class ClassA {
public void doSomethingA(){
//业务逻辑
}
}
public class ClassB {
public void doSomethingB(){
//业务逻辑
}
}
public class ClassC {
public void doSomethingC(){
//业务逻辑
}
}
//我们认为这3个类属于近邻,处理相关的业务,因此应该被认为是一个子系统的不同逻 辑处理模块,对于此子系统的访问需要通过门面进行
//门面对象
public class Facade {
//被委托的对象
private ClassA a = new ClassA();
private ClassB b = new ClassB();
private ClassC c = new ClassC();
//提供给外部访问的方法
public void methodA(){
this.a.doSomethingA();
}
public void methodB(){
this.b.doSomethingB();
}
public void methodC(){
this.c.doSomethingC();
}
}
享元模式
享元模式是池技术的重要实现方式,其定义如下:使用共享对象可有效地支持大量的细粒度的对象。
享元模式的定义为我们提出了两个要求:细粒度的对象和共享对象。
对象的内部状态和外部状态:
● 内部状态:内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变, 如我们例子中的id、postAddress等,它们可以作为一个对象的动态附加信息,不必直接储存,在具体某个对象中,属于可以共享的部分。
● 外部状态:外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态。它是一批对象的统一标识,是唯一的一个索引值。
● Flyweight:抽象享元角色,它简单地说就是一个产品的抽象类,同时定义出对象的外部状态和内部状态的接口或实现。
● ConcreteFlyweight:具体享元角色,具体的一个产品类,实现抽象角色定义的业务。需要注意的是内部状态处理与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态
● unsharedConcreteFlyweight:不可共享的享元角色,不存在外部状态或者安全要求(如线程安全)不能够使用共享技术的对象,该对象一般不会出现在享元工厂中。
● FlyweightFactory:享元工厂,职责非常简单,就是构造一个池容器,同时提供从池中获得对象的方法。
//抽象享元角色
public abstract class Flyweight {
//内部状态
private String intrinsic;
//外部状态
protected final String Extrinsic;
//要求享元角色必须接受外部状态
public Flyweight(String _Extrinsic){
this.Extrinsic = _Extrinsic;
}
//定义业务操作
public abstract void operate();
//内部状态的getter/setter
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
/*
*抽象享元角色一般为抽象类,在实际项目中,一般是一个实现类,它是描述一类事物的方法。在抽象角中,
*一般需要把外部状态和内部状态(当然了,可以没有内部状态,只有行为也是可以的)定义出来,
*避免子类的随意扩展。我们再来看具体的享元角色。
*/
//具体享元角色
public class ConcreteFlyweight1 extends Flyweight{
//接受外部状态
public ConcreteFlyweight1(String _Extrinsic){
super(_Extrinsic);
}
//根据外部状态进行逻辑处理
public void operate(){
//业务逻辑
}
}
public class ConcreteFlyweight2 extends Flyweight{
//接受外部状态
public ConcreteFlyweight2(String _Extrinsic){
super(_Extrinsic);
}
//根据外部状态进行逻辑处理
public void operate(){
//业务逻辑
}
}
//确认只需要一次赋值的属性则设置为final类型,避免无意修改导致逻辑混乱
//享元工厂
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String,Flyweight> pool= new HashMap<String,Flyweight>();
//享元工厂
public static Flyweight getFlyweight(String Extrinsic){
//需要返回的对象
Flyweight flyweight = null;
//在池中没有该对象
if(pool.containsKey(Extrinsic)){
flyweight = pool.get(Extrinsic);
}else{
//根据外部状态创建享元对象
flyweight = new ConcreteFlyweight1(Extrinsic);
//放置到池中
pool.put(Extrinsic, flyweight);
}
return flyweight;
}
}
代理模式
代理模式也叫做委托模式,它是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。
定义:为其他对象提供一种代理以控制对这个对象的访问。
● Subject:抽象主题角色,抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。
● RealSubject:具体主题角色,也叫做被委托角色、被代理角色。是业务逻辑的具体执行者。
● Proxy:代理主题角色,也叫做委托类、代理类。负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作
//抽象主题类
public interface Subject {
//定义一个方法
public void request();
}
//真实主题类
public class RealSubject implements Subject {
//实现方法
public void request() {
//业务逻辑处理
}
}
//RealSubject是一个正常的业务实现类,代理模式的核心就在代理类上
// 代理类
public class Proxy implements Subject {
//要代理哪个实现类
private Subject subject = null;
//默认被代理者
public Proxy(){
this.subject = new Proxy();
}
//通过构造函数传递代理者
public Proxy(Object...objects ){
}
//实现接口中定义的方法
public void request() {
this.before();
this.subject.request();
this.after();
}
//预处理
private void before(){
//do something
}
//善后处理
private void after(){
//do something
}
}
动态代理
什么是动态代理?动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。
相对来说,上面自己写代理类的方式就是静态代理。
//抽象主题
public interface Subject {
//业务操作
public void doSomething(String str);
}
//真实主题
public class RealSubject implements Subject {
//业务操作
public void doSomething(String str) {
System.out.println("do something!---->" + str);
}
}
//重点是我们的MyInvocationHandler
//动态代理的Handler类
public class MyInvocationHandler implements InvocationHandler {
//被代理的对象
private Object target = null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object _obj){
this.target = _obj;
}
//代理方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行被代理的方法
return method.invoke(this.target, args);
}
}
//所有通过动态代理实现的方法全部通过invoke方法调用
//动态代理类
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
{
//执行目标,并返回结果
return (T)Proxy.newProxyInstance(loader,interfaces, h);
}
}
//通知接口及实现
public interface IAdvice {
//通知只有一个方法,执行即可
public void exec();
}
public class BeforeAdvice implements IAdvice{
public void exec(){
System.out.println("我是前置通知,我被执行了!");
}
}
// 动态代理的场景类
public class Client {
public static void main(String[] args) {
//定义一个主题
Subject subject = new RealSubject();
//定义一个Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定义主题的代理
Subject proxy = DynamicProxy.newProxyInstance(
subject.getClass().getClassLoader(),
subject.getClass().getInterfaces(),handler);
//可以忽略DynamicProxy,直接创建代理
//Subject proxy = (Subject)Proxy.newProxyInstance(loader,interfaces, h);
//代理的行为
proxy.doSomething("Finish");
}
}
//运行结果:do something!---->Finish