大话设计模式 示例代码_开发人员应该知道的三种设计模式(每种都有示例代码)...

大话设计模式 示例代码

什么是设计模式? (What is a Design Pattern?)

Design patterns are design level solutions for recurring problems that we software engineers come across often. It’s not code - I repeat, CODE. It is like a description on how to tackle these problems and design a solution.

设计模式是针对我们软件工程师经常遇到的反复出现的问题的设计级别解决方案。 这不是代码-我再说一遍, CODE代码 。 就像对如何解决这些问题和设计解决方案的描述。

Using these patterns is considered good practice, as the design of the solution is quite tried and tested, resulting in higher readability of the final code. Design patterns are quite often created for and used by OOP Languages, like Java, in which most of the examples from here on will be written.

使用这些模式被认为是一种很好的做法,因为该解决方案的设计已经过尝试和测试,因此最终代码的可读性更高。 设计模式通常是为OOP语言(例如Java)创建和使用的,其中将编写此处的大多数示例。

设计模式的类型 (Types of design patterns)

There are about 26 Patterns currently discovered (I hardly think I will do them all…).

当前发现了大约26个模式(我几乎认为我不会全部完成这些…)。

These 26 can be classified into 3 types:

这26种可分为3种类型:

1. Creational: These patterns are designed for class instantiation. They can be either class-creation patterns or object-creational patterns.

1.创新的:这些模式设计用于类实例化。 它们可以是类创建模式,也可以是对象创建模式。

2. Structural: These patterns are designed with regard to a class's structure and composition. The main goal of most of these patterns is to increase the functionality of the class(es) involved, without changing much of its composition.

2.结构:这些模式是针对班级的结构和组成而设计的。 这些模式中的大多数的主要目标是在不改变其组成的大部分情况下,增加所涉及类的功能。

3. Behavioral: These patterns are designed depending on how one class communicates with others.

3.行为:这些模式的设计取决于一类与其他类之间的交流方式。

In this post, we will go through one basic design pattern for each classified type.

在这篇文章中,我们将为每种分类类型经历一个基本的设计模式。

类型1:创意-单例设计模式 (Type 1: Creational - The Singleton Design Pattern)

The Singleton Design Pattern is a Creational pattern, whose objective is to create only one instance of a class and to provide only one global access point to that object. One commonly used example of such a class in Java is Calendar, where you cannot make an instance of that class. It also uses its own getInstance()method to get the object to be used.

Singleton设计模式是一种创新模式,其目的是仅创建一个类的实例,并仅提供对该对象的一个​​全局访问点。 在Java中,此类的一个常用示例是Calendar,您无法在其中创建该类的实例。 它还使用自己的getInstance()方法来获取要使用的对象。

A class using the singleton design pattern will include,

使用单例设计模式的课程将包括:

  1. A private static variable, holding the only instance of the class.

    一个私有静态变量,保存该类的唯一实例。
  2. A private constructor, so it cannot be instantiated anywhere else.

    私有构造函数,因此无法在其他任何地方实例化它。
  3. A public static method, to return the single instance of the class.

    一个公共静态方法,返回类的单个实例。

There are many different implementations of singleton design. Today, I’ll be going through the implementations of;

单例设计有许多不同的实现。 今天,我将介绍的实现;

1. Eager Instantiation

1.渴望实例化

2. Lazy Instantiation

2.延迟实例化

3. Thread-safe Instantiation

3.线程安全的实例化

雄心勃勃 (Eager Beaver)

public class EagerSingleton {
	// create an instance of the class.
	private static EagerSingleton instance = new EagerSingleton();

	// private constructor, so it cannot be instantiated outside this class.
	private EagerSingleton() {  }

	// get the only instance of the object created.
	public static EagerSingleton getInstance() {
		return instance;
	}
}

This type of instantiation happens during class loading, as the instantiation of the variable instance happens outside any method. This poses a hefty drawback if this class is not being used at all by the client application. The contingency plan, if this class is not being used, is the Lazy Instantiation.

这种类型的实例化发生在类加载期间,因为变量实例的实例化发生在任何方法之外。 如果客户端应用程序根本不使用此类,则会带来严重的缺陷。 如果未使用此类,则应急计划是延迟实例化。

慵懒的日子 (Lazy Days)

There isn’t much difference from the above implementation. The main differences are that the static variable is initially declared null, and is only instantiated within the getInstance() method if - and only if - the instance variable remains null at the time of the check.

与上面的实现没有太大区别。 主要区别在于静态变量最初声明为null,并且仅在-并且仅当-实例变量在检查时保持为null时,才在getInstance()方法中实例化该静态变量。

public class LazySingleton {
	// initialize the instance as null.
	private static LazySingleton instance = null;

	// private constructor, so it cannot be instantiated outside this class.
	private LazySingleton() {  }

	// check if the instance is null, and if so, create the object.
	public static LazySingleton getInstance() {
		if (instance == null) {
			instance = new LazySingleton();
		}
		return instance;
	}
}

This fixes one problem, but another one still exists. What if two different clients access the Singleton class at the same time, right to the millisecond? Well, they will check if the instance is null at the same time, and will find it true, and so will create two instances of the class for each request by the two clients. To fix this, Thread Safe instantiation is to be implemented.

这解决了一个问题,但仍然存在另一个问题。 如果两个不同的客户端同时访问Singleton类(毫秒)怎么办? 好吧,他们将同时检查该实例是否为null,并发现它为true,因此将为两个客户端的每个请求创建该类的两个实例。 要解决此问题,将实现线程安全实例化。

(线程)安全是关键 ((Thread) Safety is Key)

In Java, the keyword synchronized is used on methods or objects to implement thread safety, so that only one thread will access a particular resource at one time. The class instantiation is put within a synchronized block so that the method can only be accessed by one client at a given time.

在Java中,关键字sync用于方法或对象上以实现线程安全,因此只有一个线程可以同时访问特定资源。 类实例被放置在一个同步块中,因此该方法只能在一个给定时间由一个客户端访问。

public class ThreadSafeSingleton {
	// initialize the instance as null.
	private static ThreadSafeSingleton instance = null;

	// private constructor, so it cannot be instantiated outside this class.
	private ThreadSafeSingleton() {  }

	// check if the instance is null, within a synchronized block. If so, create the object
	public static ThreadSafeSingleton getInstance() {
		synchronized (ThreadSafeSingleton.class) {
			if (instance == null) {
				instance = new ThreadSafeSingleton();
			}
		}
		return instance;
	}
}

The overhead for the synchronized method is high, and reduces the performance of the whole operation.

同步方法的开销很大,并且降低了整个操作的性能。

For example, if the instance variable has already been instantiated, then each time any client accesses the getInstance() method, the synchronized method is run and the performance drops. This just happens in order to check if the instance variables’ value is null. If it finds that it is, it leaves the method.

例如,如果实例化变量已被实例化,则每当任何客户端访问getInstance()方法时,运行synchronized方法,性能就会下降。 这只是为了检查instance变量的值是否为空。 如果找到它,则离开该方法。

To reduce this overhead, double locking is used. The check is used before the synchronized method as well, and if the value is null alone, does the synchronized method run.

为了减少这种开销,使用了双重锁定。 该检查也在synchronized方法之前使用,并且如果该值单独为null,则synchronized方法是否运行。

// double locking is used to reduce the overhead of the synchronized method
public static ThreadSafeSingleton getInstanceDoubleLocking() {
	if (instance == null) {
		synchronized (ThreadSafeSingleton.class) {
			if (instance == null) {
				instance = new ThreadSafeSingleton();
			}
		}
	}
	return instance;
}

Now onto the next classification.

现在进入下一个分类。

类型2:结构-装饰器设计模式 (Type 2: Structural - The Decorator Design Pattern)

I’m gonna give you a small scenario to give a better context to why and where you should use the Decorator Pattern.

我将给您一个小场景,以更好地说明为什么和在何处使用装饰器模式。

Say you own a coffee shop, and like any newbie, you start out with just two types of plain coffee, the house blend and dark roast. In your billing system, there was one class for the different coffee blends, which inherits the beverage abstract class. People actually start to come by and have your wonderful (albeit bitter?) coffee. Then there are the coffee newbs that, God forbid, want sugar or milk. Such a travesty for coffee!! ??

假设您拥有一家咖啡店,并且像任何新手一样,您仅以两种纯咖啡开始,即混合咖啡和深色烘焙。 在您的计费系统中,针对不同的咖啡混合物有一个类,它继承了饮料抽象类。 人们实际上开始过来喝上您的(尽管很苦?)美味的咖啡。 然后是上帝禁止的咖啡纽带,他们想要糖或牛奶。 真是太杯咖啡了!! ??

Now you need to have those two add-ons as well, both to the menu and unfortunately on the billing system. Originally, your IT person will make a subclass for both coffees, one including sugar, the other milk. Then, since customers are always right, one says these dreaded words:

现在,您还需要同时在菜单上和不幸的是在计费系统上拥有这两个附加组件。 最初,您的IT人员将为这两种咖啡创建一个子类,一种是糖,另一种是牛奶。 然后,由于客户总是对的,所以说出这些令人恐惧的话:

“Can I get a milk coffee, with sugar, please?”

“请给我加糖的牛奶咖啡吗?”

??? (???)

There goes your billing system laughing in your face again. Well, back to the drawing board….

您的计费系统再一次在您的脸上笑了起来。 好吧,回到画板……。

The IT person then adds milk coffee with sugar as another subclass to each parent coffee class. The rest of the month is smooth sailing, people lining up to have your coffee, you actually making money. ??

然后,IT人员将糖类的牛奶咖啡作为另一个子类添加到每个父级咖啡类中。 这个月的其余时间很顺利,人们排队喝咖啡,您实际上是在赚钱。 ??

But wait, there’s more!

但是,等等,还有更多!

The world is against you once again. A competitor opens up across the street, with not just 4 types of coffee, but more than 10 add-ons as well! ?

世界再次与您对立。 一个竞争者在马路对面开放,不仅有四种咖啡,而且还有十多种附加品! ?

You buy all those and more, to sell better coffee yourself, and just then remember that you forgot to update that dratted billing system. You quite possibly cannot make the infinite number of subclasses for any and all combinations of all the add-ons, with the new coffee blends too. Not to mention, the size of the final system.??

您购买了所有这些以及更多的东西,自己卖出了更好的咖啡,然后记住,您忘记更新该分散的计费系统。 对于所有附加组件的任何和所有组合,您也可能无法制作无限数量的子类,而新的咖啡混合物也不能。 更不用说最终系统的大小了。

Time to actually invest in a proper billing system. You find new IT personnel, who actually knows what they are doing and they say;

是时候实际投资在一个合适的计费系统上了。 您会发现新的IT人员,他们实际上知道他们在做什么,然后说;

“Why, this will be so much easier and smaller if it used the decorator pattern.”

“为什么,如果使用装饰器模式,这将变得更加容易并且更小。”

那到底是什么? (What on earth is that?)

The decorator design pattern falls into the structural category, that deals with the actual structure of a class, whether is by inheritance, composition or both. The goal of this design is to modify an objects’ functionality at runtime. This is one of the many other design patterns that utilize abstract classes and interfaces with composition to get its desired result.

装饰器设计模式属于结构类别,该结构类别处理类的实际结构,无论是通过继承,组合还是两者都进行。 该设计的目标是在运行时修改对象的功能。 这是利用抽象类和具有组成部分的接口来获得其预期结果的许多其他设计模式之一。

Let’s give Math a chance (shudder?) to bring this all into perspective;

让我们给数学一个机会(颤抖吗?),使这一切成为现实。

Take 4 coffee blends and 10 add-ons. If we stuck to the generation of subclasses for each different combination of all the add-ons for one type of coffee. That’s;

服用4种咖啡混合物和10种添加物。 如果我们坚持为一种咖啡的所有附加组件的每个不同组合生成子类。 那是;

(10–1)² = 9² = 81 subclasses

(10-1)²=9²= 81个子类

We subtract 1 from the 10, as you cannot combine one add-on with another of the same type, sugar with sugar sounds stupid. And that’s for just one coffee blend. Multiply that 81 by 4 and you get a whopping 324 different subclasses! Talk about all that coding…

我们从10中减去1,因为您无法将一个附加组件与另一个相同类型的附加组件组合在一起,糖和糖听起来很愚蠢。 那只是一种咖啡混合物。 将81乘以4 ,您将获得324个不同的子类! 谈论所有编码...

But with the decorator pattern will require only 16 classes in this scenario. Wanna bet?

但是在这种情况下,使用装饰器模式仅需要16个类。 想赌吗?

If we map out our scenario according to the class diagram above, we get 4 classes for the 4 coffee blends, 10 for each add-on and 1 for the abstract component and 1 more for the abstract decorator. See! 16! Now hand over that $100.?? (jk, but it will not be refused if given… just saying)

如果我们根据上面的类图来绘制场景,则对于4种咖啡混合,我们将获得4种类,对于每种附加组件,将有10种,对于抽象组件,将有1种,对于抽象装饰器,还将有1种。 看到! 16! 现在交出那100美元。 (jk,但如果给出……将不会被拒绝……只是说)

As you can see from above, just as the concrete coffee blends are subclasses of the beverage abstract class, the AddOn abstract class also inherits its methods from it. The add-ons, that are its subclasses, in turn inherit any new methods to add functionality to the base object when needed.

从上面可以看到,就像具体的咖啡混合物是饮料抽象类的子类一样,AddOn抽象类也从中继承其方法。 作为其子类的附加组件又继承了任何新方法,以便在需要时向基础对象添加功能。

Let’s get to coding, to see this pattern in use.

让我们开始编码,看看使用中的这种模式。

First to make the Abstract beverage class, that all the different coffee blends will inherit from:

首先创建Abstract饮料类,所有不同的咖啡混合物将继承自:

public abstract class Beverage {
	private String description;
    
	public Beverage(String description) {
		super();
		this.description = description;
	}
    
	public String getDescription() {
		return description;
	}
    
	public abstract double cost();
}

Then to add both the concrete coffee blend classes.

然后添加两个具体的咖啡混合类。

public class HouseBlend extends Beverage {
	public HouseBlend() {
		super(“House blend”);
	}

	@Override
	public double cost() {
		return 250;
	}
}

public class DarkRoast extends Beverage {
	public DarkRoast() {
		super(“Dark roast”);
	}

	@Override
	public double cost() {
		return 300;
	}
}

The AddOn abstract class also inherits from the Beverage abstract class (more on this below).

AddOn抽象类也继承自Beverage抽象类(有关此内容,请参见下文)。

public abstract class AddOn extends Beverage {
	protected Beverage beverage;

	public AddOn(String description, Beverage bev) {
		super(description);
		this.beverage = bev;
	}

	public abstract String getDescription();
}

And now the concrete implementations of this abstract class:

现在,这个抽象类的具体实现:

public class Sugar extends AddOn {
	public Sugar(Beverage bev) {
		super(“Sugar”, bev);
	}

	@Override
	public String getDescription() {
		return beverage.getDescription() + “ with Mocha”;
	}

	@Override
	public double cost() {
		return beverage.cost() + 50;
	}
}

public class Milk extends AddOn {
	public Milk(Beverage bev) {
		super(“Milk”, bev);
	}

	@Override
	public String getDescription() {
		return beverage.getDescription() + “ with Milk”;
	}

	@Override  public double cost() {
		return beverage.cost() + 100;
	}
}

As you can see above, we can pass any subclass of Beverage to any subclass of AddOn, and get the added cost as well as the updated description. And, since the AddOn class is essentially of type Beverage, we can pass an AddOn into another AddOn. This way, we can add any number of add-ons to a specific coffee blend.

如上所示,我们可以将饮料的任何子类传递给AddOn的任何子类,并获得增加的成本以及更新的描述。 并且,由于AddOn类本质上是饮料类型,因此我们可以将AddOn传递给另一个AddOn。 这样,我们可以将任意数量的附加组件添加到特定的咖啡混合物中。

Now to write some code to test this out.

现在编写一些代码进行测试。

public class CoffeeShop {
	public static void main(String[] args) {
		HouseBlend houseblend = new HouseBlend();
		System.out.println(houseblend.getDescription() + “: “ + houseblend.cost());

		Milk milkAddOn = new Milk(houseblend);
		System.out.println(milkAddOn.getDescription() + “: “ + milkAddOn.cost());

		Sugar sugarAddOn = new Sugar(milkAddOn);
		System.out.println(sugarAddOn.getDescription() + “: “ + sugarAddOn.cost());
	}
}

The final result is:

最终结果是:

It works! We were able to add more than one add-on to a coffee blend and successfully update its final cost and description, without the need to make infinite subclasses for each add-on combination for all coffee blends.

有用! 我们能够在咖啡混合物中添加一个以上的附加组件,并成功更新其最终成本和说明,而无需为所有咖啡混合物的每个附加组件组合创建无限子类。

Finally, to the last category.

最后,到最后一个类别。

类型3:行为-命令设计模式 (Type 3: Behavioral - The Command Design Pattern)

A behavioral design pattern focuses on how classes and objects communicate with each other. The main focus of the command pattern is to inculcate a higher degree of loose coupling between involved parties (read: classes).

行为设计模式着重于类和对象之间如何通信。 命令模式的主要焦点是灌输相关各方之间更高程度的松散耦合(请参阅:类)。

Uhhhh… What’s that?

呃……那是什么?

Coupling is the way that two (or more) classes that interact with each other, well, interact. The ideal scenario when these classes interact is that they do not depend heavily on each other. That’s loose coupling. So, a better definition for loose coupling would be, classes that are interconnected, making the least use of each other.

耦合是两个(或更多)彼此交互的类之间进行交互的方式。 这些类相互作用时的理想方案是它们之间不严重依赖。 那是松散的耦合。 因此,对于松散耦合的一个更好的定义是相互关联的类,它们之间的使用最少。

The need for this pattern arose when requests needed to be sent without consciously knowing what you are asking for or who the receiver is.

当需要在不自觉地知道您要什么或接收者是谁的情况下发送请求时,就需要使用此模式。

In this pattern, the invoking class is decoupled from the class that actually performs an action. The invoker class only has the callable method execute, which runs the necessary command, when the client requests it.

在这种模式下,调用类与实际执行操作的类分离。 调用者类仅具有可调用方法execute,当客户端请求时,该方法运行必要的命令。

Let’s take a basic real-world example, ordering a meal at a fancy restaurant. As the flow goes, you give your order (command) to the waiter (invoker), who then hands it over to the chef(receiver), so you can get food. Might sound simple… but a bit meh to code.

让我们以一个基本的实际示例为例,在一家高档餐厅点餐。 随着流程的进行,您将订单(命令)交给服务员(调用者),然后由服务员将其交给厨师(接收者),这样您就可以得到食物。 听起来很简单……但是有点编码。

The idea is pretty simple, but the coding goes around the nose.

这个想法很简单,但是编码很简单。

The flow of operation on the technical side is, you make a concrete command, which implements the Command interface, asking the receiver to complete an action, and send the command to the invoker. The invoker is the person that knows when to give this command. The chef is the only one who knows what to do when given the specific command/order. So, when the execute method of the invoker is run, it, in turn, causes the command objects’ execute method to run on the receiver, thus completing necessary actions.

技术方面的操作流程是,您要创建一个具体的命令,该命令实现Command接口,要求接收者完成一个动作,并将该命令发送给调用者。 调用者是知道何时发出此命令的人。 在给出特定命令/命令时,厨师是唯一知道该怎么做的人。 因此,当运行调用程序的execute方法时,它又使命令对象的execute方法在接收器上运行,从而完成必要的操作。

我们需要实现的是; (What we need to implement is;)

  1. An interface Command

    接口命令
  2. A class Order that implements Command interface

    实现Command接口的Order类
  3. A class Waiter (invoker)

    班级服务员(祈求者)
  4. A class Chef (receiver)

    班级厨师(接待员)

So, the coding goes like this:

因此,编码如下所示:

厨师,收货人 (Chef, the receiver)

public class Chef {
	public void cookPasta() {
		System.out.println(“Chef is cooking Chicken Alfredo…”);
	}

	public void bakeCake() {
		System.out.println(“Chef is baking Chocolate Fudge Cake…”);
	}
}

命令,界面 (Command, the interface)

public interface Command {
	public abstract void execute();
}

命令,具体命令 (Order, the concrete command)

public class Order implements Command {
	private Chef chef;
	private String food;

	public Order(Chef chef, String food) {
		this.chef = chef;
		this.food = food;
	}

	@Override
	public void execute() {
		if (this.food.equals(“Pasta”)) {
			this.chef.cookPasta();
		} else {
			this.chef.bakeCake();
		}
	}
}

服务员,调用者 (Waiter, the invoker)

public class Waiter {
	private Order order;

	public Waiter(Order ord) {
		this.order = ord;
	}

	public void execute() {
		this.order.execute();
	}
}

你,客户 (You, the client)

public class Client {
	public static void main(String[] args) {
		Chef chef = new Chef();
        
		Order order = new Order(chef, “Pasta”);
		Waiter waiter = new Waiter(order);
		waiter.execute();

		order = new Order(chef, “Cake”);
		waiter = new Waiter(order);
		waiter.execute();
	}
}

As you can see above, the Client makes an Order and sets the Receiver as the Chef. The Order is sent to the Waiter, who will know when to execute the Order (i.e. when to give the chef the order to cook). When the invoker is executed, the Orders’ execute method is run on the receiver (i.e. the chef is given the command to either cook pasta ? or bake cake?).

如您在上面看到的,客户下订单并将接收方设置为厨师。 订单被发送给服务员,服务员将知道何时执行该命令(即何时向厨师下达烹饪命令)。 当调用者被执行时,Orders的execute方法在接收者上运行(即,厨师被赋予了煮意大利面或烤蛋糕的命令)。

快速回顾 (Quick recap)

In this post we went through:

在这篇文章中,我们经历了:

  1. What a design pattern really is,

    真正的设计模式是什么
  2. The different types of design patterns and why they are different

    不同类型的设计模式及其不同之处
  3. One basic or common design pattern for each type

    每种类型都有一个基本或通用的设计模式

I hope this was helpful.  

我希望这可以帮到你。

Find the code repo for the post, here.

此处找到该帖子的代码存储库。

翻译自: https://www.freecodecamp.org/news/the-basic-design-patterns-all-developers-need-to-know/

大话设计模式 示例代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值