通常设计模式是用于解决问题的模板,可以在多种不同的情况下使用,但它并不是一个可以直接转换为代码的设计,但确实开发者奠定软件是否成功的基础。
有一些设计模式是每个开发人员都应该了解的,包括它应该在什么地方和什么时候使用,今天,就和大家讨论一下每个软件开发人员都应该知道5种重要的设计模式:
1、单例模式
这是最常用和最常见的设计模式,几乎每个应用程序都需要用到单例模式,这种模式涉及到一个单一的类,该类负责创建自己的对象,当你需要一个对象来协调跨系统的操作时,单例模式是很好的解决方式。
顾名思义,模式用于保证一个类仅有一个实例。需要声明一个私有构造函数,以防止从类外部实例化。另外,它需要声明一个singleton类型的静态字段。
public class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() {
}
public static SingletonDemo getInstance() {
if(instance == null) {
instance = new SingletonDemo();
}
return instance;
}
}
上面的代码中的getInstance()方法在运行时只创建这个类的一个实例,首选的场景:类只有一个实例,包括缓存、线程池和注册表。
单例模式的getInstance()方法并不是线程安全的。它可以被实例化不止一次,可以通过在方法上加同步调用来解决,但是这会使方法变慢。
2、工厂模式(Factory Pattern)
这里单词factory说的是工厂的意思,同样的软件工厂生产对象,它只是通过调用工厂方法,而不是调用特定类的构造函数来实现这一点。通常,对象创建的过程如下:
DemoClass demoClassObject = new DemoClass();
上述方法的问题是代码使用了具体的对象DemoClass。使用new创建对象也可以,但是它将代码紧密地耦合到了具体的类。可以通过如下的工厂模式解决该问题:
public interface Notification{
String getType();
}
public class Call implements Notification{
public String getType(){
return "call"
}
}
public class Message implements Notification{
public String getType(){
return "message"
}
}
public class NotificationFactory {
private static Map<String, Notification> instances;
static {
instances = new HashMap<>();
instances.put("call", new Call());
instances.put("message", new Message());
}
public static <T extends Notification> T getNotification(String type)
{
return (T) instances.get(type);
}
}
Notification notif = NotificationFactory.getNotification("call");
当一个类无法预料要创建哪种类的对象或是一个类需要由子类来指定创建的对象时,可以考虑使用工厂模式另外,开发人员可能不知道要构造哪种类型,例如在针对基本类型或接口进行编码时,也可以使用工厂模式。
工厂模式可以扩展系统中类的总数。每个具体的类还需要一个具体的对象,但是你可以通过参数化的Factory Method来避免。
3、建造者模式
顾名思义,建造者模式是用于构建对象,有时我们创建的对象可能很复杂,由多个子对象组成,或者需要复杂的构造过程。
建造者模式用于逐步构造一个复杂的对象,最后一步将返回该对象。构造对象的过程应该是通用的,以便可以用来创建同一对象的不同表示形式。下面的示例可以帮你更好的理解它:
public class Product {
private String id;
private String name;
private String description;
private Double value;
private Product(Builder builder) {
setId(builder.id);
setName(builder.name);
setDescription(builder.description);
setValue(builder.value);
}
public static Builder newProduct() {
return new Builder();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
public static final class Builder {
private String id;
private String name;
private String description;
private Double value;
private Builder() {
}
public Builder id(String id) {
this.id = id;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder description(String description) {
this.description = description;
return this;
}
public Builder value(Double value) {
this.value = value;
return this;
}
public Product build() {
return new Product(this);
}
}
}
Product product = Product.newProduct()
.id(1l)
.description("TV 46'")
.value(2000.00)
.name("TV 46'")
.build();
建造者模式非常类似于工厂模式,他们的主要区别在于,当你需要构建对象时,建造者模式会非常有帮助。
在建造者模式中,代码行的数量至少增加了一倍,但是在设计灵活性和可读性方面,建造者模式的优势又是很明显的。
4、适配器模式(Adapter Pattern)
这种模式将一个类的接口转换成另外一个类的的接口,它充当翻译者的角色,当两个不说共同语言的领导见面时,通常会有一位口译员坐在两者之间,翻译对话,从而实现交流。
interface Bird
{
// birds implement Bird interface that allows
// them to fly and make sounds adaptee interface
public void fly();
public void makeSound();
}
class Sparrow implements Bird
{
// a concrete implementation of bird
public void fly()
{
System.out.println("Flying");
}
public void makeSound()
{
System.out.println("Chirp Chirp");
}
}
interface ToyDuck
{
// target interface
// toyducks dont fly they just make
// squeaking sound
public void squeak();
}
class PlasticToyDuck implements ToyDuck
{
public void squeak()
{
System.out.println("Squeak");
}
}
class BirdAdapter implements ToyDuck
{
// You need to implement the interface your
// client expects to use.
Bird bird;
public BirdAdapter(Bird bird)
{
// we need reference to the object we
// are adapting
this.bird = bird;
}
public void squeak()
{
// translate the methods appropriately
bird.makeSound();
}
}
class Main
{
public static void main(String args[])
{
Sparrow sparrow = new Sparrow();
ToyDuck toyDuck = new PlasticToyDuck();
// Wrap a bird in a birdAdapter so that it
// behaves like toy duck
ToyDuck birdAdapter = new BirdAdapter(sparrow);
System.out.println("Sparrow...");
sparrow.fly();
sparrow.makeSound();
System.out.println("ToyDuck...");
toyDuck.squeak();
// toy duck behaving like a bird
System.out.println("BirdAdapter...");
birdAdapter.squeak();
}
}
如果你有两个应用程序,其中一个以XML格式输出,另一个则需要JSON输入(或其他格式),那么你将需要在两者之间使用适配器模式来无缝运行。但是适配器不能与Adaptee或Target的子类一起使用。
5、状态模式(State Pattern)
这种模式有助于我们表示对象的几种状态,假设有一个广播类的对象。它可以处于两种状态,即打开或关闭。这些状态可以用状态模式表示。
在实际应用程序中,对象具有许多状态,我们可以实现状态模式以降低系统复杂性,让我们通过一个广播示例来理解这一点:
public class Radio {
private boolean on;
private RadioState state;
public Radio(RadioState state){
this.state = state;
}
public void execute(){
state.execute(this);
}
public void setState(RadioState state){
this.state = state;
}
public void setOn(boolean on){
this.on = on;
}
public boolean isOn(){
return on;
}
public boolean isOff(){
return !on;
}
}
public interface RadioState {
void execute(Radio radio);
}
public class OnRadioState implements RadioState {
public void execute(Radio radio){
//throws exception if radio is already on
radio.setOn(true);
}
}
public class OffRadioState implements RadioState {
public void execute(Radio radio){
//throws exception if radio is already off
radio.setOn(false);
}
}
Radio radio = new Radio(new OffRadioState()); //initial status
radio.setState(new OnRadioState());
radio.execute(); //radio on
radio.setState(new OffRadioState());
radio.execute(); //radio off
上面的示例用状态模式表示无线电的不同状态。
当我们需要表示对象内部发生变化的几种状态时,在不使用状态模式的情况下,代码会变得很僵硬,并带有if-else条件语句。
状态模式需要编写许多代码,根据定义了多少种不同的状态转换方法以及对象可能处于多种状态,这样就会有数十种甚至更多不同的方法需要编写。
当然,还有许多其他有用的设计模式,但这是最常用的模式。了解上述模式后,你就可以开始学习其他模式。因为大多数应用程序是通过使用多种设计模式进行构建的