程序设计模式:继承实现与关联

面向对象程序设计原则:

  • 单一职责:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中
  • 开闭原则:面向修改关闭,面向拓展开发
  • 里氏代换:所有引用基类的地方必须能透明地使用其子类的对象
  • 依赖倒转:高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象
  • 接口隔离:客户端不应该依赖那些它不需要的接口
  • 合成复用:优先使用对象组合,而不是继承来达到复用的目的
  • 迪米特法则:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位

类继承、实现
对象关联

一、创建型模式(Creational Pattern)

创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,让用户在使用对象时无须关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展

1. 简单工厂模式

  • 由一个工厂类来负责类的生成,这可以使得「类的生成」与「程序逻辑」相脱离。利用配置文件,以在不修改任何客户端代码的情况下更换具体产品类,易于拓展。
  • 然而,其产品创建逻辑是实例的而不是抽象的,无法对产品创建逻辑拓展,一旦给某一类产品添加新的产品-,就要修改工厂方法逻

不一定需要用工厂类,可以将工厂方法静态地放到抽象产品类中

class Factory{
    public Fruit getFruit(String fr){
        if (fr == "banana") return new Banana();
        else if (fr == "watermelon") return new Watermelon();
        else if (fr == "apple") return new Apple();
        else return null;
     }
}

2. 工厂模式

  • 抽象各个工厂创建产品的逻辑(即工厂方法),可以动态扩展各个工厂的工厂逻辑。

  • 由于工厂模式中各个产品类的抽象工厂方法固定,不支持动态添加新的的新类别。

    1. 产品为先,明确产品结构
    2. 根据产品类别建立抽象工厂类:抽象不同工厂创建产品的逻辑,一般叫做 getXxxFactory
    3. 实现工厂:继承自抽象工厂族类,实现对一类产品的创建方法,对其他工厂的方法返回null
abstract class Factory{
    public abstract Apple getApple(String arg);
    public abstract Orange getOrange(String arg);
    public abstract Banana getBanana(String arg);
}
// AppleFactory
class AppleFactory extends Factory{

    @Override
    public Apple getApple(String arg) {
        if(arg == "SmallApple") return new SmallApple();
        else if(arg == "BigApple") return new BigApple();
        return null;
    }
    @Override
    public Orange getOrange(String arg) {
        return null;
    }

    @Override
    public Banana getBanana(String arg) {
        return null;
    }
}
...

3. 抽象工厂模式

与工厂模式只实现一类产品的工厂不同,抽象工厂中,会实现一簇产品的工厂方法。
image

  1. 产品为先,明确产品层级结构
  2. 工厂完全抽象为接口
  3. 实现各个产品簇的工厂
interface Factory{
    public abstract TV getTV();
    public abstract Fridge getFridge();
    public abstract Aircondition getAirCondition();
}
// TCL 产品簇工厂
class TclFactory implements Factory{
    @Override
    public TV getTV() {
        TV tv = new TclTV();
        tv.init();
        return tv;
    }
    @Override
    public Fridge getFridge() {
        Fridge fridge = new TCLFridge();
        fridge.init();
        return fridge;
    }
    @Override
    public Aircondition getAirCondition() {
        Aircondition aircondition = new TclAircondition();
        aircondition.init();
        return aircondition;
    }
}
// Hair 产品簇工厂
class HairFactory implements Factory{
    @Override
    public TV getTV() {
        TV tv = new HairTV();
        tv.init();
        return tv;
    }
    @Override
    public Fridge getFridge() {
        Fridge fridge = new HairFridge();
        fridge.init();
        return fridge;
    }
    @Override
    public Aircondition getAirCondition() {
        Aircondition aircondition = new HairAircondition();
        aircondition.init();
        return aircondition;
    }
}

4. 原型模式

通过请求原型对象复制自己来实现创建,工厂方法由原型对象的克隆方法来实现。在通过不同的方式对克隆对象进行修改以后,可以得到一系列相似但不完全相同的对象。

  • Shallow Clone:只复制它本身和值类型的成员变量,而引用类型的成员变量并没有复制
  • Deep Clone:自己和引用类型成员都实现Serializable接口
    1. 产品类实现克隆接口
    2. Prototype Manager,原型管理库,主要实现了这两个方法:add(key, object)、get(key)
// 原型管理库
class Manager{
    private HashMap<String, CarComponents> protypeTable = new HashMap<>();
    public void add(String key, CarComponents components){
        protypeTable.put(key, components);
    }

    public CarComponents get(String key, int id) throws CloneNotSupportedException {
        // 对clone出的对象稍作修改,然后返回
        CarComponents components;
        components = (CarComponents)(protypeTable.get(key)).clone();
        components.init(id);
        return components;
    }
}
// 产品抽象类
abstract class CarComponents implements Cloneable{
    protected String name;
    public abstract void init(int id);
    public void show_name(){
        System.out.println(name);
    }
    // clone
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Wheel extends CarComponents{
    @Override
    public void init(int id) {
        super.name = "Wheel " + id ;
    }
}
class BearingCircle extends CarComponents{
    @Override
    public void init(int id) {
        super.name = "BearingCircle " + id;
    }
}
class Engine extends CarComponents{
    @Override
    public void init(int id) {
        super.name = "Engine " + id;
    }
}

5. 单例模式

类自己负责创建自己的创建

  1. 构造函数全部私有,外部不可访问而不可实例化
  2. 静态变量存储类的实例(全部对象共享,确保只有一个实例)
  3. 静态工厂方法创建唯一的实例
class Single{
    private static Single sigle;
    public static Single getMultion(){
        if(sigle == null){
            sigle = new Single;
        }
        return sigle;
    }
}

创建自己的静态实例有两种时刻:在创建类时创建静态实例(饿汉式)、在初次获取静态实例时创建静态实例(懒汉式)
线程安全保护方法如下:https://haoel.blog.csdn.net/article/details/4028232

public class Singleton{
     private volatile static Singleton singleton = null ;
     private Singleton()  {}
     public static Singleton getInstance() {
         if (singleton== null )  {
             synchronized (Singleton.class) {
                 if (singleton== null) {
                     singleton= new Singleton();
                 }
             }
         }
         return singleton;
     }
}

// 利用jvm的机制保证线程安全
public class Singleton {
     private static class SingletonHolder {
         private static final Singleton INSTANCE = new Singleton();
     }
     private Singleton (){}
     public static final Singleton getInstance() {
         return SingletonHolder.INSTANCE;
     }
}

// 枚举本身就是线程安全的
public enum Singleton{
    INSTANCE;
}

6. 建造者模式

抽象产品各种组件的构建逻辑。

  1. 组件为先,确定组件关系
  2. 重写组件获取方法;抽象构建逻辑,静态化工厂方法负责构建产品
// 组装工厂
abstract class Builder {
    // 汽车组装方法
    public static void built(Builder bld) {
        bld.buildBearingCircle().getName();
        bld.buildEngine().getName();
        bld.buildWheel().getName();
    }
    // 组件获取方法
    protected abstract CarElement buildWheel();
    protected abstract CarElement buildEngine();
    protected abstract CarElement buildBearingCircle();
}

image

二、 结构型模式(Structural Pattern)

关注如何将现有类或对象组织在一起形成更加强大的结构,不同的结构型模式从不同的角度组合类或对象

  • 类的组合:继承关系和实现关系
  • 类与对象的组合:在一个类中定义另一个类的实例对象

1. 适配包装

通过继承或关联,包装对象使其适配

  1. adapter继承adaptee类,实现target接口
class Adapter extends Adaptee implements Target {
   public void request(){
       super.specialRequest();
   }
}
图片名称
  1. adapter继承target类,关联adaptee
class Adapter extends Target {
   private Adaptee adaptee;    // 维持一个对适配者的直接关联
   public Adaptee(Adaptee adaptee) {
       this.adaptee = adaptee;
   }
   @Override
   public void request(){
       adaptee.specialRequest();   // 转发调用
   }
}
图片名称
  1. 缺省适配器模式(Default Adapter Pattern):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求。

2. 代理

代理模式关注于控制对对象的访问,被代理的对象一般不需要动态注入,每种代理与外部不相关

静态代理:关联主题对象到代理中,主题对象不变化

abstract class Subject{
   public abstract void request();
}
class RealSubject extends Subject{
   @Override
   public void request() {}
}
class Proxy extends Subject {
   private Subject real_subject = new RealSubject(); // 维持一个对真实主题对象的引用
   @Override
   public void request() {
       // 执行代理
       real_subject.request();
   }
   // 添加代理成员类或代理成员方法
}
图片名称

3. 装饰

装饰器模式关注于在一个对象上动态的添加方法,同时动态地将对象注入到各种装饰器中

abstract class Component{
   public abstract void operation();
}
class ConcreteComponent extends Component{
   @Override
   public void operation(){
       System.out.println("ConcreteComponent");
   }
}
abstract class Decorator extends Component{
   protected Component component;// 1.将原有被包装对象关联到装饰器中
   public void setComponent(Component component){
       this.component =component;
   }
}
class ConcreteDecorator extends Decorator{
   @Override
   public void operation() {// 2.继承抽象类并调用被包装关联的方法
       myMethod();
       component.operation();
   }
   public void myMethod(){// 3.添加自己的方法
       System.out.println("给他装饰");
   }
}
图片名称

4. 桥接

分离正交的维度,将其抽象部分与它的实现部分解耦,使得两者都能够独立变化。最后通过接口聚合桥接回去

  • 用抽象关联取代了传统的多层继承
  • 将类之间的静态继承关系转换为动态的对象组合关系

抽象类作为主维度。接口定义分维度。分维度的抽线接口聚合在主维度中,继承主维度并通过set方法将各个分维度桥接到主维度
图片名称

5. 组合模式

容器对象Composite和叶子对象Leaf递归组合,抽象容器和叶子为Component,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象。

将Leaf(叶子构件)和 Composite(容器构件)抽象为 Component(抽象构件)。在Leaf中不应实现的方法抛出异常并返回null即可
图片名称

6. 外观模式

为子系统中的一组接口提供一个统一的入口。

图片名称

7. 享元模式

将具有相同内部状态的对象存储在享元池(Flyweight Pool)中,享元对象的外部状态通常由客户端保存。需要的时候将对象从享元池中取出,通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份

  • 内部状态(Intrinsic State):存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享
  • 外部状态(Extrinsic State):随环境改变而改变的、不可以共享的状态。
    将随时间改变、不可共享的部分作为外部状态(通过更换外部状态实现对象复用),从而减少创建对象的数量,以减少内存开销和提高性能。

角色:
image

三、行为模式

关注系统中对象之间的交互,研究系统在运行时对象之间的相互通信与协作,进一步明确职责划分:

  • 类行为型模式:使用继承关系在几个类之间分配行为,主要通过多态等方式来分配父类与子类的职责
  • 对象行为型模式:使用对象的关联关系来分配行为,主要通过对象关联等方式来分配多个类的职责

1. 责任链模式

将事务的处理职责划分成链,事务沿着这条链分步处理,直到处理它为止。
image

2. 命令/动作/事务模式

将发出命令的责任和执行命令的责任分开。从而让你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

请求对象Invoker关联Command对象,并通过Command对象执行请求。
在ConcreateCommand对象中引用请求处理者Receiver,并在excute方法中处理调用Receiver.action()处理请求。
命令队列:增加一个CommandQueue类,由该类负责存储多个命令对象,而不同的命令对象可以对应不同的请求接收者
记录请求日志:将命令对象通过序列化保存下来
宏命令:是一个具体命令类,它拥有一个集合,在该集合中包含了对其他命令对象的引用。当调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法。
image

public class Invoker {
    private Command command;
    //构造注入
    public Invoker(Command command) {
        this.command = command;
    }
    //设值注入
    public void setCommand(Command command) {
        this.command = command;
    }
    //业务方法,用于调用命令类的execute()方法
    public void call() {
        command.execute();
    }
}

public abstract class Command {
    public abstract void execute();
}
public class ConcreteCommand extends Command {
    private Receiver receiver; //维持一个对请求接收者对象的引用
    public void execute() {
        receiver.action(); //调用请求接收者的业务处理方法action()
    }
}

public class Receiver {
    public void action() {
        //具体操作
    }
}

3. 解释模式

4. 迭代器模式

将遍历数据的行为从聚合对象中分离出来,封装在迭代器对象中

  • 在迭代器 ConcreteIterator中关联集合Aggregate对象,实现迭代方法
  • 在ConcreteAggregate集合对象提供迭代器工厂方法
    image

5. 中介者模式

用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

  • 中介对象ConcreteMediator聚合同事对象;同事对象通过register方法注册到集合中;通信方法operation封装与其他同事的通信
  • 同事对象Colleague关联Mediator对象,通过它调用其他同事的方法
    image
public abstract class Mediator {
    protected ArrayList<Colleague> colleagues = new ArrayList<Colleague>(); //用于存储同事对象
    //注册方法,用于增加同事对象
    public void register(Colleague colleague) {
        colleagues.add(colleague);
    }
    //声明抽象的业务方法
    public abstract void operation();
}
public class ConcreteMediator extends Mediator {
    //实现业务方法,封装同事之间的调用
    public void operation() {
        ......
        ((Colleague)(colleagues.get(0))).method1(); //通过中介者调用同事类的方法
        ......
    }
}

public abstract class Colleague {
    protected Mediator mediator; //维持一个抽象中介者的引用
    public Colleague(Mediator mediator) {
        this.mediator=mediator;
    }
    public abstract void method1(); //声明自身方法,处理自己的行为
    //定义依赖方法,与中介者进行通信
    public void method2() {
        mediator.operation();
    }
}
public class ConcreteColleague extends Colleague {
    public ConcreteColleague(Mediator mediator) {
        super(mediator);
    }
    //实现自身方法
    public void method1() {
        ......
    }
}

7. 观察者模式

定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。

观察者 ConcreateObserver 关联 被观察者的状态,观察者可以修改
将需要被通知的对象的观察者聚合到 ConcreateSubject的观察者集合
image

public abstract class Subject {
    //定义一个观察者集合用于存储所有观察者对象
    protected ArrayList observers<Observer> = new ArrayList();
    //注册方法,用于向观察者集合中增加一个观察者
    public void attach(Observer observer) {
        observers.add(observer);
    }
    //注销方法,用于在观察者集合中删除一个观察者
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    //声明抽象通知方法
    public abstract void notify();
}
public class ConcreteSubject extends Subject {
    private State subjectState;
    //实现通知方法
    public void notify() {
        //遍历观察者集合,调用每一个观察者的响应方法
        for(Object obs:observers) {
            ((Observer)obs).update();
        }
    }
}

public interface Observer {
    public void update(); //声明响应方法
}
public class ConcreteObserver implements Observer {
	private State oberverState;
    public void update() { //实现响应方法
        //具体响应代码
    }
}

8 访问者模式

表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

Visitor定义对各种元素的抽象操作,在ConcreateVisitor实例中实现了各种具体的操作
在元素类Element中,accept方法接受visitor的访问,visitor将对此元素操作
image

public abstract class Visitor {
    public abstract void visit(ConcreteElementA elementA);
    public abstract void visit(ConcreteElementB elementB);
    public void visit(ConcreteElementC elementC) {
        //元素ConcreteElementC操作代码
    }
}
public class ConcreteVisitor extends Visitor {
    public void visit(ConcreteElementA elementA) {
        //元素ConcreteElementA操作代码
    }
    public void visit(ConcreteElementB elementB) {
        //元素ConcreteElementB操作代码
    }
}

public interface Element {
    public void accept(Visitor visitor);
}
public class ConcreteElementA implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationA() {
        //业务方法
    }
}

6. 备忘录模式

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以在以后将对象恢复到原先保存的状态。

独立的备忘录类Memento记录原发器的状态
image

package designpatterns.memento;
public class Originator {
    private String state;
    public Originator(){}
    //创建一个备忘录对象
    public Memento createMemento() {
        return new Memento(this);
    }
    //根据备忘录对象恢复原发器状态
    public void restoreMemento(Memento m) {
        state = m.state;
    }
    public void setState(String state) {
        this.state=state;
    }
    public String getState() {
        return this.state;
    }
}

//备忘录类,默认可见性,包内可见
package designpatterns.memento;
class Memento {
    private String state;
    Memento(Originator o) {
        state = o.getState();
    }
    void setState(String state) {
        this.state=state;
    }
    String getState() {
        return this.state;
    }
}

package designpatterns.memento;
public class Caretaker {
    private Memento memento;
    public Memento getMemento() {
        return memento;
    }
    public void setMemento(Memento memento) {
        this.memento=memento;
    }
}

9. 状态模式

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

将不同状态的行为抽象出来为State
Context对象根据值,关联抽象状态的不同实例;调用状态的方法,表现出不同的行为
共享状态:
image

public abstract class State {
    //声明抽象业务方法,不同的具体状态类可以有不同的实现
    public abstract void handle();
}
public class ConcreteState extends State {
    public void handle() {
        //方法具体实现代码
    }
}
public class Context {
    private State state; //维持一个对抽象状态对象的引用
    private int value;  //其他属性值,该属性值的变化可能会导致对象的状态发生变化

    public void setState(State state) {
        this.state = state;
    }
	public void changeState(){
		//判断属性值,根据属性值进行状态转换
		if (value == 0) this.setState(new ConcreteStateA());
		else if (value == 1) this.setState(new ConcreteStateB());
		 ......
	}
    public void request() {
        //其他代码
        state.handle(); //调用状态对象的业务方法
        //其他代码
    }
}

10. 策略、政策模式

定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法可以独立于使用它的客户变化。

image

public abstract class Strategy {
    public abstract void algorithm();  //声明抽象算法
}
public class ConcreteStrategyA extends Strategy {
    //算法的具体实现
    public void algorithm() {
        //算法A
    }
}

public class Context {
    private Strategy strategy; //维持一个对抽象策略类的引用
    //注入策略对象
    public void setStrategy(Strategy strategy) {
        this.strategy= strategy;
    }
    //调用策略类中的算法
    public void algorithm() {
        strategy.algorithm();
    }
}

11 模板模式

定义算法的框架,而将一些具体步骤延迟到实现子类。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤。
image

划分各个步骤,将步骤抽象为抽象方法,在子类中实现
使用钩子方法、钩子变量,来对步骤进行分支

public abstract class AbstractClass {
    //模板方法
    public void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        primitiveOperation3();
	}
    //基本方法—具体方法
    public void primitiveOperation1() {
        //实现代码
    }
    //基本方法—抽象方法
    public abstract void primitiveOperation2();

    //基本方法—钩子方法
    public void primitiveOperation3()    {  }
}

public class ConcreteClass extends AbstractClass {
    public void primitiveOperation2() {
        //实现代码
    }
    public void primitiveOperation3() {
        //实现代码
    }
posted @ 2021-04-21 10:23  minLoong  阅读(339)  评论(0)    收藏  举报