设计模式--简化解释(一)——创建型设计模式

cnsuifeng

1.创建型设计模式
2.结构型设计模式
3.行为型设计模式

创建型设计模式

简而言之

创建型设计模式关注的是如何实例化一个或者一组相关的对象。

维基百科

在软件工程中,创建型设计模式是用于解决对象创建机制,尝试在指定场景下使用合理的方式来创建对象的设计模式。基本的创建方式对导致设计问题或者增加设计的复杂度。创建型设计模式通过一些控制对象创建的手段来解决这些问题。

? 简单工厂

现实例子

考虑一下,你需要建造一个房子,然后需要几扇门。如果每次需要一扇门的时候,你都穿上木匠的衣服然后在房间里左门会造成很大的混乱。取而代之是你需要买一个从工厂里做好的。

简而言之

对客户端来说,简单工厂模式仅仅生成一个实例,不需要暴露给客户端人户实例化的逻辑。

维基百科说

在面向对象编程中(OOP),工厂是一个用于创建对象的对象,正式的工厂是一个方法或者函数,在某些方法调用的时候返回不同的原型或者对象,我们认为这个对象是新的。

编程实例
首先我们有一个们的接口和实现

public interface Door {
    float getWidth();
    float getHeight();
}
public class WoodenDoor implements Door {
    private float width;
    private float height;

    public WoodenDoor(float width, float height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public float getWidth() {
        return 0;
    }

    @Override
    public float getHeight() {
        return 0;
    }
}

然后我们需要一个生产并返回门的工厂

public class DoorFactory {
    public static Door makeDoor(float width,float height)
    {
        return new WoodenDoor(width,height);
    }
}

使用方式如下

Door door = DoorFactory.makeDoor(1200L,2100L);
System.out.println("Door Width:"+door.getWidth());
System.out.println("Door Height:"+door.getHeight());

何时使用
当创建一个不仅仅是几条赋值语句同时包含一些逻辑的对象的时候,把创建对象的代码放到一个专用的工厂中而不是到处赋值相同的代码,这是情理之中的。

? 工厂方法

现实例子

考虑一个人事部经理的例子. 不可能所有的岗位都有一个人来面试. 根据职位空缺,他将面试的步骤安排给不同的人.

简而言之

提供一种将实例化逻辑委托给子类的方式.

维基百科说

在给予类的编程中,工厂方法模式是一个创建型的模式,这个模式用于解决建对象的问题而无需指定要创建的精确的类。通过调用工厂方法(在接口中指定并由子类实现,或者在基类中实现),或者通过派生类(而不是调用构造函数)来实现,这是通过创建对象来完成的。

编程示例
参考上边人事部经理的例子。首先我们有一个面试官的接口和一些实现。

public interface Inteviewer {
    void askQuestions();
}
public class Developer implements Inteviewer {
    @Override
    public void askQuestions() {
        System.out.println("Ask about Design Patterns");
    }
}
public class CommunityExecutive implements Inteviewer {
    @Override
    public void askQuestions() {
        System.out.println("Ask about community build");
    }
}

现在我们创建 HiringManager

public abstract class HiringManager {
    protected abstract Inteviewer makeInteviewer();

    public void takeInteview()
    {
        Inteviewer inteviewer = makeInteviewer();
        inteviewer.askQuestions();
    }
}

现在和人子类都可以实现该类来提供需要的面试官

public class DevelopmentManager extends HiringManager {
    @Override
    protected Inteviewer makeInteviewer() {
        return new Developer();
    }
}
public class CommunityManager extends HiringManager {
    @Override
    protected Inteviewer makeInteviewer() {
        return new CommunityExecutive();
    }
}

使用举例

public class Client {
    public static void main(String[] args) {
        HiringManager manager = new DevelopmentManager();
        manager.takeInteview();

        manager = new CommunityManager();
        manager.takeInteview();
    }
}

何时使用?
当一个类中有一些通用的处理但是子类需要在运行时决定的时候使用。换句话说,客户端不知道需要的精确的子类。

? 抽象工厂

现实举例

扩展我们的简单工厂模式的门的例子。考虑到你的需求,你可能从一个木门的商店购买一个木门,从一个铁门的商店购买一个铁门,或者从另外的相关的商店购买一个PVC门。除此之外你可能需要一个有不同技能的伙计帮你装门,例如木匠来装木门,焊接工装铁门。正如你看到的那样,现在门之间有一个依赖,木门需要木匠,铁门需要焊接工等等。

简而言之

一个工厂的工厂。一个工厂在不指定具体的类的情况下将独立但相关的工程组合在一起。

维基百科说

抽象工厂模式提供了一种方式来封装一度独立的工厂,这些工厂有相同的主题当时没有指定具体的类。

编程示例

翻译上边门的例子. 首先我们有门的接口和几个门的实现

public interface Door {
    String getDescription();
}
public class WoodenDoor implements Door {
    @Override
    public String getDescription() {
        return "I am a wooden door";
    }
}
public class IronDoor implements Door {
    @Override
    public String getDescription() {
        return "I am an iron door";
    }
}

然后每一种门我们有一些安装专家

public interface DoorFittingExpert {
    String getDescription();
}
public class Carpenter implements DoorFittingExpert {
    @Override
    public String getDescription() {
        return "I can only fit wooden doors";
    }
}
public class Welder implements DoorFittingExpert {
    @Override
    public String getDescription() {
        return "I can only fit iron doors";
    }
}

现在我们需要一个抽象工厂来帮我们决定相关对象的族。例如木门工厂需要生产木门和木门安装专家,铁门工厂需要生产铁门和铁门安装专家。

public interface DoorFactory {
    Door makeDoor();
    DoorFittingExpert makeFittingExper();
}
public class WoodenDoorFactory implements DoorFactory {
    @Override
    public Door makeDoor() {
        return new WoodenDoor();
    }

    @Override
    public DoorFittingExpert makeFittingExper() {
        return new Carpenter();
    }
}
public class IronDoorFactory implements DoorFactory {
    @Override
    public Door makeDoor() {
        return new IronDoor();
    }

    @Override
    public DoorFittingExpert makeFittingExper() {
        return new Welder();
    }
}

使用方式如下:

DoorFactory doorFactory = new WoodenDoorFactory();
        Door door = doorFactory.makeDoor();
        DoorFittingExpert expert = doorFactory.makeFittingExper();
        System.out.println("Door:"+door.getDescription());
        System.out.println("Expert:"+expert.getDescription());

正如上边看到的一样,木门工厂封装了carpenterwooden door,铁门工厂封装了iron doorwelder.因此工厂帮我们确信每一个创建的门都不会有错误的安装的专家

何时使用
当有相关的复杂的创建逻辑的依赖的时候

? 建造者

现实举例

设想一下你在Hardee,你要点餐,我们会说:Big Hardee,他们不会问任何问题就会把饭端过来。这是一个简单工厂的例子。但是有种情况下创建逻辑包含几个步骤。例如你想吃一个自助的Subway,汉堡怎么做,例如面包用什么样的,用什么样的酱汁,想要什么样的奶酪。这种情况下,建造者模式将会拯救我们。

简而言之

避免构造函数污染的情况下为对象创造不同的特性。当一个对象有多个特性或者创建对象包含几个步骤的时候使用。

维基百科说

建造者模式是一种对象创建软件设计模式,其目的是找到一种解决方案,以解决可伸缩构造函数的反模式。

说道这里,让我添加一点关于伸缩构造函数反模式的内容。在某些地方,我们都看到了如下的构造函数。:

public Deal(int size, boolean cheese ,boolean pepperoni, boolean tomato, boolean lettuce)
{
}

正如你所看到的;构造函数参数的数量很快就会失去控制,并且很难理解参数的排列。另外,如果你想在未来增加更多的选项,这个参数列表还可以继续增长。这被称为伸缩构造函数反模式。

程序示例
明智的选择是使用建造者模式。首先我们要有一个我们要做的汉堡(burger)

package com.suifeng.designpattern.builder;

public class Burger {
    private int size;
    private boolean cheese;
    private boolean pepperoni;
    private boolean lettuce;
    private boolean tomato;

    public Burger(BurgerBuilder builder)
    {
        this.size = builder.size;
        this.cheese=builder.cheese;
        this.pepperoni = builder.pepperoni;
        this.lettuce = builder.lettuce;
        this.tomato = builder.tomato;
    }

    @Override
    public String toString() {
        return "Burger{" +
                "size=" + size +
                ", cheese=" + cheese +
                ", pepperoni=" + pepperoni +
                ", lettuce=" + lettuce +
                ", tomato=" + tomato +
                '}';
    }

    static class BurgerBuilder{
        private int size;
        private boolean cheese;
        private boolean pepperoni;
        private boolean lettuce;
        private boolean tomato;

        public BurgerBuilder(int size) {
            this.size = size;
        }

        public BurgerBuilder addCheese()
        {
            this.cheese = true;
            return this;
        }

        public BurgerBuilder addPepperoni()
        {
            this.pepperoni = true;
            return this;
        }

        public BurgerBuilder addLettuce()
        {
            this.lettuce = true;
            return this;
        }

        public BurgerBuilder addTomato()
        {
            this.tomato = true;
            return this;
        }

        public Burger build()
        {
            return new Burger(this);
        }
    }
}

使用方式如下

Burger burger = new Burger.BurgerBuilder(12).addCheese().addLettuce().build();
        System.out.println(burger);

何时使用
当一个对象有几个特性并且需要避免构造器伸缩。与工厂模式的主要不同是:工厂模式的创建过程只有一个步骤而建造者模式需要多个步骤。

? 原型

现实举例

还记得多里吗?就是那只被克隆的山羊。我们不关注细节,这里的关键就是克隆。

简而言之

通过克隆的方式根据现有对象来创建新对象

维基百科说

原型模式是软件开发中的一个创建型设计模式。当要创建的对象类型由一个原型实例决定时,使用原型模式,该实例被克隆以产生新的对象。

简而言之,它允许您创建一个现有对象的副本,并根据您的需要修改它,而不是从头开始创建一个对象并设置它。

Programmatic Example

Java中可以使用clone方法

public class Sheep implements Cloneable {

    private String name;
    private String category;

    public Sheep(String name, String category) {
        this.name = name;
        this.category = category;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", category='" + category + '\'' +
                '}';
    }

    public Sheep clone()
    {
        Object obj = null;

        try {
            obj =super.clone();

            return (Sheep) obj;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return null;
    }
}

克隆方式如下

public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("Jolly","Mountain Sheep");

        Sheep dolly = sheep.clone();
        dolly.setName("Dolly");

        System.out.println(dolly);
    }
}

何时使用?

当需要的对象与存在的对象相似的时候或者相比于克隆创建成本比较高的情况.

? 单例

现实举例

同一时间一个国家只有一个总统。 当指责需要的时候,采取行动的是同一个总统. 在这里总统就是单例的

简而言之

一个特定的类确保只创建一个对象。

维基百科说

在软件工程中,单例模式是一种软件设计模式,它将类的实例化限制为一个对象。 当需要一个对象来协调整个系统中的操作时,这很有用。

单例模式实际上被认为是一种反模式,应该避免过度使用。它并不一定是坏的,并且可以有一些有效的用例,但是应该谨慎使用,因为它在您的应用程序中引入了一个全局状态,并且在一个地方对它进行更改可能会影响到其他领域,因此调试可能变得非常困难。另一件不好的事情是,它使您的代码紧密耦合,另外对单例对象的模拟是困难的。

编程示例
创建一个单例,需要将构造函数私有,禁用可控和扩展,通过创建一个静态的变量来保存实例。

public class President {
    private static President INSTANCE ;

    private President()
    {

    }

    public static President getInstance()
    {
        if(INSTANCE == null)
        {
            INSTANCE = new President();
        }

        return INSTANCE;
    }


}

使用方式如下

 President president1 = President.getInstance();
        President president2 = President.getInstance();

        System.out.println(president1 == president2);
阅读 1.3k

JAVA进阶
JAVA,设计模式,多线程,Spring

为了梦,坚守

24 声望
1 粉丝
0 条评论
你知道吗?

为了梦,坚守

24 声望
1 粉丝
宣传栏