Java 设计模式总结

《武林外传》老白曾经说过这样一句话。高手就是手里无刀,心中也无刀。 类似于设计模式,你不知不觉中已经融进你的代码中了,但你并不知已经运用了。下面我总结几个我觉得比较常用的设计模式。

1:设计模式分类

总体来说设计模式分为三大类

创建型模式, 共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式, 共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式, 共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

大家没有必要死记硬背哪一种模式属于哪一种类型,面试如果问到,因为不会背而挂,只能说这家公司不去也罢。

我们需要真正理解,为什么工厂方法模式也是创建型模式,因为它是一个 factory,他创建一个对象供你使用。又比如适配器模式为什么是结构型模式,它是不是从”顺序性编码“变成了”分支形编码“,改变了代码的结构。所以你需要真正理解每一种设计模式,做到不自觉的运用到你的代码中去。

2:单例模式

单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

//懒汉 线程不安全class SingletonDemo1 {
    private SingletonDemo1(){}
    private static SingletonDemo1 instance = null;
    public static SingletonDemo1 getInstance() {        if (instance == null) {            instance = new SingletonDemo1();        }        return instance;    }}
//懒汉 线程安全 直接加锁class SingletonDemo2 {
    private SingletonDemo2() {}
    private static SingletonDemo2 instance = null;
    public static synchronized SingletonDemo2 getInstance() {        if (instance == null) {            instance = new SingletonDemo2();        }        return instance;    }}
// Double Checkpublic class SingletonDemo2 {    private volatile static Singleton instance;
    private Singleton() {    }
    public static Singleton getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new Singleton();                }            }        }        return instance;    }}

//饿汉 线程安全class SingletonDemo3 {
    private SingletonDemo3() {}
    private static SingletonDemo3 instance = new SingletonDemo3();
    public static SingletonDemo3 getInstance() {        return instance;    }}
//内部类 线程安全,并且懒加载class SingletonDemo4 {
    private SingletonDemo4() {}
    private static class InnerSingletonDemo4 {        private static final SingletonDemo4 instance = new SingletonDemo4();    }
    public static final SingletonDemo4 getInstance() {        return InnerSingletonDemo4.instance;    }}
// 枚举方式。最为推荐的一种方式public enum SingletonDemo5 {    INSTANCE;
    public void doSomeThing() {    }}

复制代码

3: 适配器模式

举个例子,比较插头的电源为 110v,但是我们现在想要 220v 的电源。所以我们就可以用适配器模式,使这个类符合我现有的要求。

同样,在编写 JAVA 程序时,我们可能会遇到这样一种情况:我们需要一个类 A 来实现接口 B,但是类 A 并没有实现接口 B 中的所有方法,而类 A 是不能被改变的,这时我们可以创建一个类 C,它继承类 A 并实现接口 B,这个类 C 就是一个适配器。适配器中的代码将接受你所拥有的接口,并产生你所需要的接口。适配器模式有两张:类适配器模式和对象适配器模式。

// 假设这个规定电源为220vinterface A {
    void method220v();
}
//这个类实现的为110v的方法class B {
    void method110v() {        System.out.println("110v");    }}
// 适配为既可以110v,也可以220vclass C extends B implements A {
    @Override    public void method220v() {
        System.out.println("220v");    }}

复制代码

4:装饰着模式

装饰者模式通过组合的方式扩展对象的特性,这种方式允许我们在任何时候对对象的功能进行扩展甚至是运行时扩展,而若我们用继承来完成对类的扩展则只能在编译阶段实现,所以在某些时候装饰者模式比继承(inheritance)要更加灵活。

所谓装饰者,实际上就是将装饰的内容的以零部件的形式构建起来,然后经过组装形成一个一个新的逻辑内容,动态而灵活的组建逻辑性能。

// 形状Shape circle = new Circle();
// 加了红色的形状Shape redCircle = new RedShapeDecorator(new Circle());  // 加了红色的长方形Shape redRectangle = new RedShapeDecorator(new Rectangle());

复制代码

5:策略模式

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

应用实例:

  • 诸葛亮的锦囊妙计,每一个锦囊就是一个策略。

  • 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。

  • JAVA AWT 中的 LayoutManager。

优点:

  • 算法可以自由切换。

  • 避免使用多重条件判断。

  • 扩展性良好。

缺点:

  • 策略类会增多。

  • 所有策略类都需要对外暴露。

使用场景:

  • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

  • 一个系统需要动态地在几种算法中选择一种。

  • 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。举一个例子:很简单的一个例子。比如人,人分为男人,女人,甚至不清楚性别的人。但这三种类型的人,都有不同的行为。那么我们在描述这些不同行为的时候,一般我们做法就是如下:

if (male) {   //...} else if (female) {   //...} else {   //...}

复制代码

类似如上。很多个 if,else 进行嵌套。这样非常的难看,不优雅。如果我们用策略模式替换,会怎么样。

  • 第一步,定义一个 Person 类接口

  • 第二步定义 person 的继承类,如男人,女人等等

  • 第三步定义一个 enum 类,表示可选择性。

  • 最后一步定义一个策略选择器

public interface Person {    void executeStrategy();}
public class MalePerson implements Person {    public void executeStrategy() {        System.out.println("我是男性");    }}
public class FemalePerson implements Person {    public void executeStrategy() {        System.out.println("我是女性");    }}
public class UnknownPerson implements Person {    public void executeStrategy() {        System.out.println("未知性别");    }}

public enum SexEnum {    MALE("male", "男性"),    FEMALE("female", "女性"),    UNKNOWN("unknown", "未知");
    private String code;    private String sex;
    SexEnum(String code, String sex) {        this.code = code;        this.sex = sex;    }}
// 这块在实际开发中,我们会用factory结合spring来做这块逻辑public class ContextStrategy {    private MalePerson malePerson = new MalePerson();    private FemalePerson femalePerson = new FemalePerson();    private UnknownPerson unknownPerson = new UnknownPerson();
    public Person getPersonStrategy(SexEnum sexEnum) {        if ("male".equals(sexEnum.getCode())) {            return malePerson;        } else if ("female".equals(sexEnum.getCode())) {            return femalePerson;        } else {            return unknownPerson;        }    }}

public class Main {    public static void main(String[] args) {        ContextStrategy strategy = new ContextStrategy();        strategy.getPersonStrategy(**SexEnum.MALE**).executeStrategy();        strategy.getPersonStrategy(**SexEnum.FEMALE**).executeStrategy();        strategy.getPersonStrategy(**SexEnum.UNKNOWN**).executeStrategy();    }}
// 结果如下:// 我是男性// 我是女性// 未知性别

复制代码

其实我们可以看到。策略选择器是传入一个 Enum 类,然后根据传入 Enum 的不同,选择了不同的继承类。从而实现了 if else。优雅的过渡。可以看到,代码非常的优雅易懂,主代码,没有 if else 分支。但同时代码量多了起来。不过也很容易维护。

在实际项目中,我们一般会使用工厂模式 + 策略模式一起使用来达到减少 if else 的操作,策略模式在实际使用中非常的多,建议同学们务必掌握。

6:责任链模式

// 校验器接口public interface Validator<T> {    Validator<T> next();    boolean handle(T t) throws FordealException;}
public class BasicParameterValidator implements Validator<ValuationWO> {    @Autowired    private Validator<ValuationWO> tokenValidator;
    @Override    public Validator<ValuationWO> next() {        return tokenValidator;    }
    @Override    public boolean handle(ValuationWO valuationWO) throws Exception {        return next().handle(valuationWO);    }}

复制代码

最后

以上举了几个简单的例子,做一个抛砖引玉,还是希望同学们可以花一点时间,去了解下比较常用的设计模式。不需要背下来,多看看别人写的代码,然后尝试去模仿,慢慢的,你就会发觉,你就开始融会贯通了。做到手里无刀,心中也无刀,但实际上又快有准。

```python
class BertPooler(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.dense = nn.Linear(config.hidden_size, config.hidden_size)
        self.activation = nn.Tanh()

    def forward(self, hidden_states):
        # We "pool" the model by simply taking the hidden state corresponding
        # to the first token.
        first_token_tensor = hidden_states[:, 0]
        pooled_output = self.dense(first_token_tensor)
        pooled_output = self.activation(pooled_output)
        return pooled_output
from transformers.models.bert.configuration_bert import *
import torch
config = BertConfig.from_pretrained("bert-base-uncased")
bert_pooler = BertPooler(config=config)
print("input to bert pooler size: {}".format(config.hidden_size))
batch_size = 1
seq_len = 2
hidden_size = 768
x = torch.rand(batch_size, seq_len, hidden_size)
y = bert_pooler(x)
print(y.size())
```

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值