资讯专栏INFORMATION COLUMN

设计模式--简化解释(二)——结构型设计模式

miya / 1735人阅读

摘要:创建型设计模式结构型设计模式行为型设计模式结构型设计模式简而言之结构模式主要涉及对象的组成,或者是实体如何相互使用。

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

结构型设计模式

简而言之

结构模式主要涉及对象的组成,或者是实体如何相互使用。或者,另一个解释是,他们帮助回答“如何构建一个软件组件?”

维基百科说

在软件工程中,结构设计模式是通过识别实体之间关系的简单方法来简化设计的设计模式。
?适配器模式

现实举例

考虑一下你的记忆卡上有一些图片,你需要把它们转移到你的电脑上。为了转移它们,你需要某种与你的计算机端口兼容的适配器,这样你就可以将存储卡附加到你的电脑上。在这个例子中读卡器就是适配器。
另一个例子是著名的电源适配器;一个三脚插头不能连接到两个电源插座,它需要使用一个电源适配器,使它与两个电源插座兼容。
另一个例子是一个译者翻译一个人对另一个人说的话。

简而言之

适配器模式允许您在适配器中包装一个不兼容的对象,使其与另一个类兼容。

维基百科说

在软件工程中,适配器模式是一种软件设计模式,它允许将现有类的接口用作另一个接口。它通常用于使现有的类与其他类一起工作,而无需修改它们的源代码。

编程示例

考虑一个游戏,一个猎人追捕狮子。
首先我有一个狮子(Lion)的接口和所有要实现类型的狮子。

public interface Lion {
    void roar();
}
public class AsianLion implements Lion {
    @Override
    public void roar() {
        System.out.println("AsianLion roar");
    }
}
public class AfricanLion implements Lion {
    @Override
    public void roar() {
        System.out.println("AfricanLion roar");
    }
}

猎人希望所有捕获的狮子都能实现Lion的接口。

public class Hunter {
    public void hunt(Lion lion)
    {
        lion.roar();
    }
}

现在在我们的游戏里增加一个"野狗"(WildDog),猎人也可以捕获。但是我们不能直接这样做,因为野狗(WildDog)有一个不同的接口。为了兼容我们的猎人(hunter),我们必须创建一个适配器来使之兼容。

public class WildDog {
    public void bark()
    {
        System.out.println("WildDog bark");
    }
}
public class WildDogAdapter implements Lion {
    private WildDog wildDog;

    public WildDogAdapter(WildDog wildDog) {
        this.wildDog = wildDog;
    }

    @Override
    public void roar() {
        this.wildDog.bark();
    }
}

现在 WildDog 可以在我们的游戏里使用 WildDogAdapter来代替.

 WildDog wildDog = new WildDog();
        WildDogAdapter adapter = new WildDogAdapter(wildDog);
        Hunter hunter = new Hunter();
        hunter.hunt(adapter);
?桥接模式

现实举例

考虑你有一个不同页面的网站,你应该允许用户改变主题。你会怎么做?为每个主题创建多个页面的多个副本,或者仅仅根据用户的喜好创建多带带的主题并加载它们?桥式模式允许你做第二件事。

简而言之

桥式模式是倾向于选择组合而不是继承。实现细节从层次结构推送到另一个具有独立层次结构的对象。

维基百科说

桥式模式是软件工程中使用的一种设计模式,它的意思是“将抽象与实现分离开来,以便两者能够独立地变化”。

编程示例

翻译一下上边的Web页面(Web Page)的例子。首先是独立的WebPage层次

public interface WebPage {
    String getContent();
}
public class About implements WebPage {
    private Theme theme;

    public About(Theme theme) {
        this.theme = theme;
    }

    @Override
    public String getContent() {
        return "About page in "+theme.getColor();
    }
}
public class Career implements WebPage {
    private Theme theme;

    public Career(Theme theme) {
        this.theme = theme;
    }

    @Override
    public String getContent() {
        return "Career Page in "+theme.getColor();
    }
}

独立的主题层次

public interface Theme {
    String getColor();
}
public class AquaTheme implements Theme {
    @Override
    public String getColor() {
        return "Light blue";
    }
}
public class DarkTheme implements Theme {
    @Override
    public String getColor() {
        return "Dark Black";
    }
}
public class LightTheme implements Theme {
    @Override
    public String getColor() {
        return "Off White";
    }
}

And both the hierarchies

Theme aquaTheme = new AquaTheme();
Theme darkTheme = new DarkTheme();

WebPage about = new About(aquaTheme);
WebPage career = new Career(aquaTheme);
System.out.println(career.getContent());
System.out.println(about.getContent());

System.out.println("");

about = new About(darkTheme);
career = new Career(darkTheme);
System.out.println(career.getContent());
System.out.println(about.getContent());
? 组合模式

现实举例

每个组织都是由雇员组成的。每个雇员都有相同的特性,即有工资,有一些职责,可以或不可以向某人报告,可以或不可能有一些下属等。

简而言之

组合模式允许客户以统一的方式处理单个对象

维基百科说

在软件工程中,组合模式是一个分而治之的设计模式。
组合模式描述了以相同的方式对待一组对象和单个对象。 组合的意图是将对象“组合”到树结构中,以表示部分整个层次结构。 实现组合模式可以让客户端对单个对象和组合进行统一处理。

编程示例

参考我们上边雇员的例子。我们又几种类型的雇员。

public interface Employee {
    String getName();
    void setSalary(float salary);
    float getSalary();
    String getRole();
}
public class Developer implements Employee {
    private String name;
    private float salary;
    private String role;

    public Developer(String name, float salary) {
        this.name = name;
        this.salary = salary;
        this.role = "Developer";
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setSalary(float salary) {
        this.salary = salary;
    }

    @Override
    public float getSalary() {
        return this.salary;
    }

    @Override
    public String getRole() {
        return role;
    }
}
public class Designer implements Employee{
    private String name;
    private float salary;
    private String role;

    public Designer(String name, float salary) {
        this.name = name;
        this.salary = salary;
        this.role = "Designer";
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setSalary(float salary) {
        this.salary = salary;
    }

    @Override
    public float getSalary() {
        return this.salary;
    }

    @Override
    public String getRole() {
        return role;
    }
}

下面我们用组织来保存几种不同类型的雇员。

public class Orgnization {
    private List employees = new ArrayList<>();

    public void addEmployee(Employee employee)
    {
        employees.add(employee);
    }

    public float getSalary()
    {
        float total = 0;
        for(Employee employee : employees)
        {
            total += employee.getSalary();
        }

        return total;
    }
}

使用方式如下

 Employee employee1 = new Developer("John Doe",12000);
        Employee employee2 = new Designer("Jane Doe",15000);

        Orgnization orgnization = new Orgnization();
        orgnization.addEmployee(employee1);
        orgnization.addEmployee(employee2);

        System.out.println(orgnization.getSalary());
☕ 装饰者模式

现实举例

假设你经营一家提供多种服务的汽车服务商店。那么如何计算要收取的费用呢?您可以选择一个服务并动态地将提供的服务的价格添加到最终成本。这里的每一种服务都是装饰者。

简而言之

装饰者模式允许您通过将对象在一个装饰者类的对象中进行包装,从而在运行时动态地更改对象的行为。

维基百科说

在面向对象编程中,装饰者模式是一种设计模式,它允许将行为添加到单个对象中,无论是静态的还是动态的,都不会影响来自同一类的其他对象的行为。 装饰者模式通常对坚持单一责任原则非常有用,因为它允许在具有独特关注点的类之间划分功能。

编程示例
我们以咖啡举例,首先我们有一个简单的实现了咖啡接口的咖啡。

public interface Coffee {
    float getCost();
    String getDescription();
}
public class SimpleCoffee implements Coffee {
    @Override
    public float getCost() {
        return 10;
    }

    @Override
    public String getDescription() {
        return "simpleCoffee";
    }

    @Override
    public String toString() {
        return "SimpleCoffee";
    }
}

我们希望使代码可扩展,以便在需要时允许选项进行修改。让我们做一些附加组件(decorator)

public class MilkCoffee implements Coffee {
    private Coffee coffee;

    public MilkCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public float getCost() {
        return coffee.getCost()+2;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription()+",milk";
    }
}
public class VanillaCoffee implements Coffee{

    private Coffee coffee;

    public VanillaCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public float getCost() {
        return coffee.getCost()+3;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription()+",vanilla";
    }
}
public class WhipCoffee implements Coffee {
    private Coffee coffee;

    public WhipCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public float getCost() {
        return coffee.getCost()+5;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription()+",whip";
    }
}

Lets make a coffee now

Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getCost());
System.out.println(coffee.getDescription());

coffee = new MilkCoffee(coffee);
System.out.println(coffee.getCost());
System.out.println(coffee.getDescription());

coffee = new VanillaCoffee(coffee);
System.out.println(coffee.getCost());
System.out.println(coffee.getDescription());

coffee = new WhipCoffee(coffee);
System.out.println(coffee.getCost());
System.out.println(coffee.getDescription());
? 门面模式

现实举例

你怎么打开电脑?“按下电源键”你说!这就是你所相信的,因为你使用的是一个简单的界面,电脑在外部提供,在内部它需要做很多事情来实现它。这个复杂子系统的简单接口是一个门面。

简而言之

门面模式提供了一个复杂子系统的简化接口。

维基百科说

门面模式是为更大的代码体(如类库)提供简化接口的对象。

编程示例

以我们上边的计算机为例。首先这是我们的计算机。

public class Computer {
    public void getElectricShock()
    {
        System.out.println("Ouch");
    }

    public void makeSound()
    {
        System.out.println("Beep beep!");
    }

    public void showLoadingScreen()
    {
        System.out.println("Loading..");
    }

    public void bam()
    {
        System.out.println("Ready to be used!");
    }

    public void closeEverything()
    {
        System.out.println("closeEverything");
    }

    public void sooth()
    {
        System.out.println("Zzzzz");
    }

    public void pullCurrent()
    {
        System.out.println("Haaah");
    }
}

下面是门面

public class ComputerFacade {
    private Computer computer;

    public ComputerFacade(Computer computer) {
        this.computer = computer;
    }

    public void turnOn()
    {
        computer.getElectricShock();
        computer.makeSound();
        computer.showLoadingScreen();
        computer.bam();
    }

    public void turnOff()
    {
        computer.closeEverything();
        computer.pullCurrent();
        computer.sooth();
    }
}

下面开始使用门面

Computer computer = new Computer();
ComputerFacade facade = new ComputerFacade(computer);

facade.turnOn();
System.out.println("============================");
 facade.turnOff();
? 享元模式

现实举例

你曾经在某个摊位上喝过新鲜的茶吗?他们经常做的比你要求的多并把剩下的留给其他顾客,以节省资源,例如气体等。Flyweight模式就是分享。

简而言之

它通过尽可能多地与类似对象共享来最小化内存使用或计算开销。

维基百科说

在计算机编程中,享元是一种软件设计模式。享元是一个对象,它通过与其他类似对象共享尽可能多的数据来最小化内存使用;当一个简单的重复表示使用不可接受的内存时,它是一种使用大量对象的方法。

编程示例
翻译一下我们上边茶水的例子。首先我们有茶的类型和茶具。

public class KarakTea {
}
public class TeaMaker {
    private Map availableTea = new HashMap<>();

    public KarakTea make(String preference)
    {
        if(!availableTea.containsKey(preference))
        {
            availableTea.put(preference,new KarakTea());
        }

        return availableTea.get(preference);
    }
}

然后我们有茶社来接单和提供服务。

public class TeaShop {
    private TeaMaker teaMaker;
    private Map orders = new HashMap<>();

    public TeaShop(TeaMaker teaMaker) {
        this.teaMaker = teaMaker;
    }

    public void takeOrder(String teaType,int table)
    {
        orders.put(table,teaMaker.make(teaType));
    }

    public void serve()
    {
        Set> entrySet = orders.entrySet();
        for(Map.Entry entry : entrySet)
        {
            System.out.println("Serving tea to table#"+entry.getKey());
        }
    }
}

使用方式如下

TeaMaker teaMaker = new TeaMaker();
TeaShop shop = new TeaShop(teaMaker);
shop.takeOrder("less sugar", 1);
shop.takeOrder("more milk", 2);
shop.takeOrder("without sugar", 3);

shop.serve();
? 代理模式

现实举例

你曾经用过门禁卡吗?打开这扇门有多种选择,即可以使用门禁卡打开,也可以通过按一个绕过安全按钮的按钮打开。 门的主要功能是打开,但是在它上面添加了一个代理来添加一些功能。让我用下面的代码示例更好地解释一下。

简而言之

使用代理模式,一个类代表另一个类的功能。

维基百科说

代理,在其最一般的形式中,是一个类作为其他东西的接口。 代理是由客户端调用的包装器或代理对象,以访问实际服务对象。代理的使用可以简单地转发到实际对象,或者提供额外的逻辑。 在代理的额外功能中可以提供,例如在实际对象上的操作是资源密集型的缓存,或者在调用实际对象的操作之前检查先决条件。

编程示例

上边安全门的例子。首先我们有一个门的接口和一个门的实现

public interface Door {
    void open();
    void close();
}
public class LabDoor implements Door {
    @Override
    public void open() {
        System.out.println("Opening lab door");
    }

    @Override
    public void close() {
        System.out.println("Closing lab door");
    }
}

我们有一个来历来确保我们想要的门。

public class SecuredDoor {
    private Door door;

    public SecuredDoor(Door door) {
        this.door = door;
    }

    public void open(String pwd) {
        if(authenticate(pwd))
        {
            door.open();
        }
        else
        {
            System.out.println("Big no! It ain"t possible.");
        }
    }

    private boolean authenticate(String pwd)
    {
        return "$ecr@t".equals(pwd);
    }

    public void close() {
        this.door.close();
    }
}

使用方式如下

Door door = new LabDoor();
SecuredDoor securedDoor = new SecuredDoor(door);

securedDoor.open("invalid");
//securedDoor.open("$ecr@t");

还有一个例子是某种形式的数据映射的实现。例如我最近编写了一个MongoDB的ODM。在mongodb周围利用魔术方法__call()我写了一个代理,所有的方法调用都被代理到原生的mongo类。检索的结果作为返回的数据,如果find或者findOne的数据映射到某个类,这类将会代替cursor返回。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71057.html

相关文章

  • PHP 设计模式概述

    摘要:创建型模式主要有以下五种简单工厂模式和工厂方法模式抽象工厂模式单例模式建造者模式原型模式在设计模式一书中将工厂模式分为两类工厂方法模式与抽象工厂模式。 一、 设计模式(Design pattern)是什么 设计模式是一套被反复使用、多数人知晓、经过分类编目的代码设计的经验总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 二、 为什么会有设计模式 在软件开发过...

    IntMain 评论0 收藏0
  • 记录一些用来学习设计模式的博客及书籍:

    摘要:里氏代换原则里氏代换原则面向对象设计的基本原则之一。里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。里氏代换原则是对开闭原则的补充。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。 一、设计模式的六大原则: 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不...

    NSFish 评论0 收藏0
  • 第6章:可维护性软件构建方法 6.3可维护性构建技术

    摘要:遵循特定规则,利用操作符,终止节点和其他非终止节点,构造新的字符串非终结符是表示字符串的树的内部节点。语法中的生产具有这种形式非终结符终结,非终结符和运算符的表达式语法的非终结点之一被指定为根。 大纲 基于状态的构建 基于自动机的编程 设计模式:Memento提供了将对象恢复到之前状态的功能(撤消)。 设计模式:状态允许对象在其内部状态改变时改变其行为。 表驱动结构* 基于语法的构...

    young.li 评论0 收藏0
  • 设计模式--简化解释(一)——创建型设计模式

    摘要:维基百科在软件工程中,创建型设计模式是用于解决对象创建机制,尝试在指定场景下使用合理的方式来创建对象的设计模式。维基百科说建造者模式是一种对象创建软件设计模式,其目的是找到一种解决方案,以解决可伸缩构造函数的反模式。 1.创建型设计模式2.结构型设计模式3.行为型设计模式 创建型设计模式 简而言之 创建型设计模式关注的是如何实例化一个或者一组相关的对象。 维基百科 在软件工程中,创建型...

    iKcamp 评论0 收藏0

发表评论

0条评论

miya

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<