我是靠谱客的博主 稳重水池,最近开发中收集的这篇文章主要介绍设计模式(Design Pattern)设计模式(Design Pattern),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

设计模式(Design Pattern)

使用设计模式可以有效的提高开发效率和软件的健壮性等特性。设计模式可以分为下面几类:

  • 结构型模式
  • 行为类模式
  • 创建型模式

设计模式有很多种,本文会给出一些有代表性的设计模式。

结构型模式:

  • Adapter 适配器模式
  • Decorator 装饰器模式
  • Façade 外观模式
  • Proxy 代理模式

行为类模式:

  • Strategy 策略模式
  • Template Method 模板模式
  • Iterator 迭代器模式
  • Observer 观察者模式
  • Visitor 访问者模式

创建型模式:

  • Factory method 工厂方法模式
  • Abstract factory 抽象工厂模式

在给出设计模式之前,先给出委托的概念。

委托(delegation)

委托的作用

委托是一项提高软件复用性的技术,相较于继承机制,委托更加灵活多变,能够有效的降低耦合度。很多设计模式都是讲继承和委托结合使用。委托发生在对象层面,而继承发生在类层面。

委托的实现

总的思路是:把A的功能委派给B来实现。

结构框图:

例子:

在这里插入图片描述

由于动物有多个行为属性,而每个属性又有多个取值,这个需求如果使用继承实现,会导致大量的组合。

下面给出使用委托机制的实现

// 定义两个抽象的行为接口
interface Flyable{
    public void fly();
}
interface Quackable{
    public void quack();
}

//再给出两个接口的实现,每个接口可以有多个实现,但这里每个接口只给出一个实现
class FlyWithWings implements Flyable{
    @override
    public void fly(){
        System.out.println("fly with wings");
    }
}
class Quack implements Quackable{
    @override
    public void fly(){
        System.out.println("quack like duck");
    }
}

上面的这些代码实际上是设计了被委托对象(也就是委托中的B)。下面再给出A如何进行委托。

interface Ducklike extends Flyable,Quackable{
    //这里通过接口的组合,定义了行为的组合
}
public class Duck implements Ducklike{//这里的Duck类通过继承Ducklike接口,拥有了相应的行为
    //这里是在设置委托。这里直接进行了绑定,是委托中的组合(Composition),还有其他的几种委托,将在下面给出。
    Flyable flyBehavior = new FlyWithWings();
    Quackable quackBehavior = new Quack();
    //这里通过委托来实现具体的行为
    @override
    public void fly(){
        this.flyBehavior.fly()
    }
    @override
    public void quack(){
        this.quackBehavior.fly()
    }
}

接下来给出客户端使用方法。

//客户端的使用很简单
Duck d = new Duck();
d.fly();
d.quack();

委托的分类

委托根据具体的实现还可以分为几类。

  • 依赖(Dependency):A use B
  • 关联(Association):A has B
  • 组合(Composition)/聚合(aggregation):A owns B4

其中,组合和聚合可以视作关联的两种具体形态。

下面解释这几个类型的区别。

Dependency:临时的委托

通过方法的参数或者在方法的局部中使用时发生联系。

class Duck{
    //这里不再保存Flyable对象
    
    void fly(Flyable f){
        //通过外部传入参数来进行委托
        f.fly();
    }
}
//外部调用的时候,需要传入一个参数
Flyable f = new FlyWithWings();
Duck d = new Duck();
d.fly(f);

从上面的代码可以看出,Duck类中不再保存对应的被委托者(B)的对象,转而使用传入参数来进行委托。所以这个委托只是临时的。

Association:永久性的委托

与上面的临时性委托相反,这里A会保存B的对象,从而达到建立永久性的联系。

Association可以分为Composition和Aggregation,两者的区别是,前者保存被委托者的对象时直接绑定了具体的对象,而后者仅仅是声明,未进行绑定。

Composition:

class Duck{
    //这里直接进行了绑定
    Flyable f = new FlyWithWings();
    
    void fly(){
        f.fly();
    }
}

Aggregation:

class Duck{
    //这里仅仅声明了变量
    Flyable f;
    //这里根据外界传入的参数来进行绑定
    void Duck(Flyable f){
        this.f = f;
    }
    void fly(){
        f.fly();
    }
}

Adapter 适配器模式

这个模式用来解决接口不兼容的问题。通过增加一个接口,将已存在的子类封装起来,然后client面向这个新增的接口进行编程,这样既解决了不兼容问题,也隐藏了具体子类。

结构框图:

在这里插入图片描述
适配器模式可以通过继承和委托两种方式实现。

例子:

一个LegacyRectangle类有一个display()方法,接收参数是左上角坐标+宽+高。但是客户端想接收左上角坐标+右下角坐标。这样就造成了不兼容的问题。我们使用适配器模式来解决这个问题。

设计图:

在这里插入图片描述
代码:

interface Shape{
    //client期望的参数列表形式
    void dispaly(int x1, int y1, int x2, int y2);
}

class LegacyRectangle{
    //我们实际的参数列表形式,和上面的不兼容
	void dispaly(int x1, int y1, int w, int h){
        ...
    }
}

class Rectangle implements Shape{//Adaptor类实现抽象接口
	void display(int x1, int y1, int x2, int y2){
		new LegacyRectangle().display(x1, y1, x2-x1, y2-y1);
    }
}

class Client { //客户端可以直接对抽象接口进行编程
    Shape shape = new Rectangle();
    public display() { 
        shape.display(x1, y1, x2, y2);
	} 
}

Decorator 装饰器模式

这个模式主要用来解决子类特征组合的问题。对每一个特征构造子类,通过委托机制增加到对象上。

设计框图:

在这里插入图片描述
其中Decorator抽象类是所有装饰类的基类,里面包含的成员变量component指向了被装饰的对象。

例子:

对于一个最基本的Stack类,实现具有多种功能的子类。如SecureStack、UndoStack、SynchronizedStack。

设计图:

在这里插入图片描述

代码:

下面的代码是实现一个最基本的Stack类,当作被装饰物。

interface Stack { 
    void push(Item e); 
    Item pop();
}
public class ArrayStack implements Stack { //实现一个最基本的Stack类,当作被装饰物
    ... //rep
	public ArrayStack() {...} 
	public void push(Item e) { 
        ...
	} 
	public Item pop() { 
        ...
	} 
	...
}

再写Decorator抽象类

//给出一个用于 decorator的基础类
public abstract class StackDecorator implements Stack { 
    protected final Stack stack; //这个成员变量用来保存被装饰对象
    public StackDecorator(Stack stack) { 
    	this.stack = stack;
	} 
    //下面的Stack基础功能仍然是通过委托实现
	public void push(Item e) { 
        stack.push(e);
	} 
	public Item pop() { 
        return stack.pop();
	}
	...
}

下面给出具体的装饰,只给出一个,其他的特征写法类似

public class UndoStack extends StackDecorator { 
    private final UndoLog log = new UndoLog(); 
    public UndoStack(Stack stack) { 
        super(stack);
	} 
    public void push(Item e) { 
        super.push(e); //基础功能通过委托实现
        log.append(UndoLog.PUSH, e);//增加新特性
	}
    public void undo() {//增加新特性
    	//实现修饰的功能
        ...
    }
} 

再给出使用方法

Stack s = new ArrayStack();//创建基础类

Stack t = new UndoStack(new ArrayStack());//创建一个具undo特征的stack

Stack t = new SecureStack(new SynchronizedStack( new UndoStack(s)))//创建一个多特征的Stack

Façade 外观模式

Façade模式很简单,目的是提供一个统一的接口来取代一系列小接口调用,相当于对复杂 系统做了一个封装,简化客户端使用。

设计框图:

在这里插入图片描述

这个模式很简单就不写了。

Proxy 代理模式

某个对象比较“敏感”“私密”/“贵重”,不希望被 client直接访问到,故设置 proxy,在二者之间建立防火墙。这个模式和适配器模式相似,但是针对的应用场景不同,适配器主要解决的是Client和ADT之间的接口不兼容问题,代理模式是为了隔离对复杂对象的访问,降低访问的代价。

设计框图:

在这里插入图片描述

例子:

从磁盘加载图片,有时候仅仅只是需要图片的对象,不需要真正的从磁盘加载图片,如果直接创建Image对象会产生很高的代价。

在这里插入图片描述

代码:

public interface Image{
    void display();
}

public class RealImage implements Image {
	private String fileName;
	public RealImage(String fileName){
		this.fileName = fileName;
		loadFromDisk(fileName);
	}
    @Override
    public void display() {}
    private void loadFromDisk(String fileName){}//每次创建都要从磁盘加载,代价高 
}

public class ProxyImage implements Image {
	private Image realImage;
    private String fileName;
    public ProxyImage(String fileName){
    	this.fileName = fileName;//这里创建一个Image就不需要从磁盘加载
    }
    @Override
    public void display() {//调用display,真正用到Image时候再开始加载
        if(realImage == null){
        realImage = new RealImage(fileName);//通过委托机制
    }
    realImage.display();
    }
}

Strategy 策略模式

这个模式也很简单,就是有多种不同的算法来实现同一个任务,但需要client根据需要 动态切换算法,而不是写死在代码里。为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例。

设计框图:

在这里插入图片描述

这个很简单也不写了。

Template Method 模板模式

这个方法的思想是,给出做事情的步骤顺序,但是每一步有很多种实现方法。

设计框图:

在这里插入图片描述

其中TemplateAbstraction是一个抽象类,规定了方法有哪些步骤以及步骤的顺序。然后具体的步骤实现是在子类中。

例:

造一辆汽车的步骤顺序是一样的,但是每个步骤不同的汽车公司不一样。

设计如下:

在这里插入图片描述

代码:

抽象类:

public abstract class CarBuilder { 
    protected abstract void BuildSkeleton(); 
    protected abstract void InstallEngine(); 
    protected abstract void InstallDoor();

    public void BuildCar() { //造车通用逻辑
        BuildSkeleton(); 
        InstallEngine();
        InstallDoor();
    } 
}

子类:

public class PorcheBuilder extends CarBuilder { 
    protected void BuildSkeleton() { 
        System.out.println("Building Porche Skeleton");
	protected void InstallEngine() { 
        System.out.println("Installing Porche Engine");
	}
	protected void InstallDoor() { 
        System.out.println("Installing Porche Door");
	} 
}
    
public class BeetleBuilder extends CarBuilder { 
    protected void BuildSkeleton() { 
        System.out.println("Building Beetle Skeleton");
	}
	protected void InstallEngine() { 
        System.out.println("Installing Beetle Engine");
	}
	protected void InstallDoor() { 
        System.out.println("Installing Beetle Door");
	} 
}

使用方法:

public static void main(String[] args) { 
    CarBuilder c = new PorcheBuilder(); 
    c.BuildCar();
    
    c = new BeetleBuilder(); 
    c.BuildCar(); }

Iterator 迭代器模式

提供遍历容器中内容的方式。

设计框图:

在这里插入图片描述
先实现Iterable接口,再写一个具体的Iterator类

例子:

public class Pair<E> implements Iterable<E> { 
    private final E first, second; 
    public Pair(E f, E s) { 
        first = f; second = s; 
    } 
    public Iterator<E> iterator() { 
        return new PairIterator();
	}
    //内部类
	private class PairIterator implements Iterator<E> { 
        private boolean seenFirst = false, seenSecond = false; 
        
        public boolean hasNext() { 
            return !seenSecond; 
        } 
        public E next() { 
            if (!seenFirst) { 
                seenFirst = true; 
                return first; 
            }
            if (!seenSecond) { 
                seenSecond = true; 
                return second; 
            } 
            throw new NoSuchElementException();
		}
        public void remove() { 
            throw new UnsupportedOperationException();
        } 
	}
}

Observer 观察者模式

这是.一种“发布-订阅”形式,发布方的变化,会通知订阅方 。订阅方在发布方进行注册。这个模式可以类比粉丝和偶像,粉丝希望得知偶像的一举一动,于是粉丝就去偶像那里注册,偶像一旦有消息,就会推送给已经注册的粉丝(即回调粉丝的特定功能)。java提供了Observer接口,可以直接使用。

回调的目的大致可以分为:

  • 推送通知
  • 推送数据
  • 拉取数据

设计框图:

在这里插入图片描述

例子:

public class Subject {//这里是偶像
    private List<Observer> observers = new ArrayList<Observer>();//维护粉丝列表
        private int state;//偶像的状态
        public int getState() {return state;}//供粉丝和外界获取状态
        public void setState(int state) {//设置状态
            this.state = state;
            notifyAllObservers();//状态更改之后,通知所有粉丝
    }
    public void attach(Observer observer){observers.add(observer);}//添加一个粉丝
    //这里也可以有删除粉丝的功能
    private void notifyAllObservers(){
        for (Observer observer : observers) {
        observer.update();
    	}
    }
}
public abstract class Observer {
    protected Subject subject;//这里保存了粉丝的偶像,这个属性可有可无,如果没有的话,粉丝就是完全被动的
    public abstract void update();//供偶像回调的函数
}
public class BinaryObserver extends Observer{//一个具体的粉丝
    public BinaryObserver(Subject subject){
        this.subject = subject;//指定自己的偶像
        this.subject.attach(this);
    }
    @Override
    public void update() {//定制的行为
        System.out.println( "Binary String: " +
        Integer.toBinaryString(
        subject.getState() ) );
    }
}
public class ObserverPatternDemo {//客户端代码
    public static void main(String[] args) {
        Subject subject = new Subject();
        new HexaObserver(subject);
        new OctalObserver(subject);
        new BinaryObserver(subject);
        System.out.println("First state change: 15");
        subject.setState(15);
        System.out.println("Second state change: 10");
        subject.setState(10);
    }
}

Visitor 访问者模式

这个模式为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下在需要时委托机制通过接入ADT。这个模式使用了双向委托。

设计框图:

在这里插入图片描述

例子

对不同商品进行结算,不同的商品,计算总价的方式不同。

代码:

/* Abstract element interface (visitable) */
public interface ItemElement {//这是一个visitable的接口
	public int accept(ShoppingCartVisitor visitor);
}
/* Concrete element */
public class Book implements ItemElement{
    private double price;
    ...
    int accept(ShoppingCartVisitor visitor) {//实现visit方法
    	visitor.visit(this);//把this传入
    }
}
public class Fruit implements ItemElement{
    private double weight;
    ...
    int accept(ShoppingCartVisitor visitor) {//实现visit方法
    	visitor.visit(this);//把this传入
    }
}
/* Abstract visitor interface */
public interface ShoppingCartVisitor {//visitor接口
    int visit(Book book);
    int visit(Fruit fruit);
}
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
    public int visit(Book book) {//用来计算book的总价
        int cost=0;
        if(book.getPrice() > 50){
            cost = book.getPrice()-5;
        }else
            cost = book.getPrice();
        System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost);
        return cost;
	}
    public int visit(Fruit fruit) {//用来计算fruit的总价
        int cost = fruit.getPricePerKg()*fruit.getWeight();
        System.out.println(fruit.getName() + " cost = "+cost);
        return cost;
    }
}

客户端代码:

public class ShoppingCartClient {
    public static void main(String[] args) {
        ItemElement[] items = new ItemElement[]{
        new Book(20, "1234"),new Book(100, "5678"),
        new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};
        int total = calculatePrice(items);
        System.out.println("Total Cost = "+total);
    }
    private static int calculatePrice(ItemElement[] items) {
        ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
        int sum=0;
        for(ItemElement item : items)
        sum = sum + item.accept(visitor);
        return sum;
    }
}

Factory Method 工厂方法模式

这个模式可以叫做虚拟构造器,使用户自定义的构造对象的方法。

结构框图:

在这里插入图片描述

这个模式很简单,就不举例了。要注意一点,最好把工厂类中的创建方法改成static,这样就不需要再多创建一个工厂对象。

Abstract Factory 抽象工厂模式

这个模式相当于工厂方法模式的升级版本,工厂方法模式只能产生特定的某个产品,而抽象工厂模式可以产生一个由多个产品的组合体。实质两者是一致的。

例子:

在这里插入图片描述

从上面可以看出,一个抽象工厂实际上是多个工厂的特定组合。

最后

以上就是稳重水池为你收集整理的设计模式(Design Pattern)设计模式(Design Pattern)的全部内容,希望文章能够帮你解决设计模式(Design Pattern)设计模式(Design Pattern)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(28)

评论列表共有 0 条评论

立即
投稿
返回
顶部