几种简单的设计模式

1.模板模式

模板设计模式简单理解就是模板化,标准化,也算解耦合的一种形式。比如有两个类都实现了一个接口,比如学生类和老师类,都继承了清华大学的类,那么怎区别他们使老师还是学生呢,很简单,让学生和老师类都有一个type方法,表明自己的身份,向外介绍的时候就说”我是清华大学的老师或者我是清华大学的学生“,这里面”我是清华大学的”就是一个模板,后边老师和学生就是他们自己特有的方法。那么模板就可以提出来放到清华大学类里边,成为公用的,而具体的老师和学生就需要具体实现的,那么我需要三个类,清华大学,老师,学生。

abstract class qinghua{
    public void show(){
        System.out.println("我是清华大学的"+getType());//模板
    }
    abstract String getType();//需要实现的
}
class teacher extends qinghua{
    @Override
    String getType() {
        return "老师";
    }
}
class student extends qinghua{
    @Override
    String getType() {
        return "学生";
    }
}
public class Demo {
    public static void main(String[] args) throws IOException {
       student s =new student();
       s.show();
    }
}

打印“我是清华大学的学生”。所以模板模式其实就是在父类中进行了抽取。结构是非常简单的

图例:

2.装饰模式(包装模式)

装饰模式就是对某个类进行包装,目的是改写已存在的类的某个方法或某些方法,那么有一个例子是改写jdbc链接池链接connection的关闭方法。在以前开发有手写链接池的,连接池获取连接,链接用完后应该放回到池中而不是关闭掉,如果按照原始的DriverManager.getConnection()得到的connection是MySQL驱动实现好的子类,因为connection本身是接口,只提供了标准方法,具体实现都是子类,那么close方法就是直接关闭掉,但我们不想关闭掉,想把链接放回池去,所以要改写connection的close方法,但是又不能影响其他的方法,connection的具体子类我们又没有源码,怎么办呢?这就用到了装饰模式。

//步骤:
/*1、编写一个类,实现与被包装类相同的接口。(具备相同的行为)
2、定义一个被包装类类型的变量。
3、定义构造方法,把被包装类的对象注入,给被包装类变量赋值。
4、对于不需要改写的方法,调用原有的方法。
5、对于需要改写的方法,写自己的代码。*/
public class MyConnection implements Connection {
    private Connection con;
    private LinkedList<Connection> pool;

    public MyConnection(Connection con, LinkedList<Connection> pool) {
        this.con = con;
        this.pool = pool;
    }

    @Override
    public void close() throws SQLException {
        pool.addLast(con);
    }
    @Override
    public Statement createStatement() throws SQLException {
        return con.createStatement();
    }

那么我们看MyConnection,这个类实现了connection接口,实现了它所有的方法,并改写了close方法。我们把具体的connection子类通过构造方法传进来,并使用它实现其他方法。最后完成了对close的包装。这和代理模式是有些像的。

图例:

3.适配器模式

适配器就是作为调用者和拥有者之间的桥梁,调用者想调用的和拥有者能给的并不一致,所以需要中间人进行协调,这里的问题是,那为什么不重新写一个呢,一定要调用吗,所以适配器并不是在设计时就定好的,而是在开发中因为需要将一个功能放到新环境中时,与新环境不能兼容而需要修改的时候才用的。因为我们不想改变原有的类,但是又需要它适用新环境。比如手机上的存储卡,需要能在电脑上读取,就需要读卡器,再比如,电源是220v的,但是我的电脑用的是110v的,怎么办?不能把电线改成110v的吧,所以有转换器,将220v转换成110v,这就是适配器。

首先看一下java里边的例子,监听器的适配器,在java的GUI中,有一个窗口类Frame,可以创建一个窗口,但是窗口的关闭按钮不能用,必须给按扭添加关闭事件,而在java中是通过事件监听器对关闭来设置的。代码如下:

public static void main(String[] args) throws IOException {
       Frame f =new Frame();
       f.setBounds(100,200,300,300);
       f.addWindowListener();//此处参数需要添加一个监听器,但是监听器是接口,不能实例化,所以需要我们自定义实现并重写相关方法
    }

那么我实现一下windosListener

public class MyListener implements WindowListener {
    @Override
    public void windowOpened(WindowEvent e) {
        
    }

    @Override
    public void windowClosing(WindowEvent e) {

    }

    @Override
    public void windowClosed(WindowEvent e) {

    }

    @Override
    public void windowIconified(WindowEvent e) {

    }

    @Override
    public void windowDeiconified(WindowEvent e) {

    }

    @Override
    public void windowActivated(WindowEvent e) {

    }

    @Override
    public void windowDeactivated(WindowEvent e) {

    }
}

发现实现后需要超多方法需要重写,但是我们不需要这些,我们只需要其中的一个windowClosing方法也就是关闭,当然其他我们可以什么都不做,但是这么多方法都是冗余的并不是我们想要的,怎么办呢?

我们可以再写一个抽象类,实现windosListener并重写那些方法,再用我们自定义的监听器继承这个抽象类,因为抽象类已经将方法全部实现了,我们的监听器只需要挑选自己想要的就可以了,(上边的装饰模式中,Myconnection也是要重写很多方法,也可以增加个dapter,但是dapter也要重写很多方法,所以显得多此一举)

public class MyListener extends MyAdater {

    @Override
    public void windowClosing(WindowEvent e) {
       
    }
}

这里MyAdater就是一个中间人,适配器。再java中,也提供了一个写好的适配器WindowAdapter,所以直接使用就可以,不用自己实现了

public static void main(String[] args) throws IOException {
       Frame f =new Frame();
       f.setBounds(100,200,300,300);

       f.addWindowListener(new WindowAdapter() {
           @Override
           public void windowClosing(WindowEvent e) {
               super.windowClosing(e);
           }
       });
    }

我们点进去看一下源码,发现和我们的MyAdater一样,实现了WindowListener接口,当然还实现了其他接口,使其适用范围更广。

我们再来看另一个例子,我们现在的手机都只有一个typec接口,是没有耳机接口的,那么我们想插耳机怎么办呢,可以用一个转接线就可以了。

这里要明确几个对象

1.目标接口:或者叫标准接口,我们期望的接口。比如耳机接口

2.被适配对象:现有的类,但是和我们要的不兼容。比如手机接口

3.适配器:可以将上面两个合在一起的类,转接线

public class TypeC {
    //现存接口,需要适配的类
   public void typcIO(){
       System.out.println("typec接口");
   }
}
public interface Omtp {
    public void omtpIo();//耳机能使用的接口,omtp接口
}
public class TypeCAndOmtpAdapter extends TypeC implements Omtp{
    @Override
    public void omtpIo() {//改写目标接口,接上现有类的接口
        System.out.println("可以链接typec的omtp接口");
        this.typcIO();
    }
}

使用的时候,直接使用适配器类就可以了。

 public static void main(String[] args) throws IOException {
       Omtp erji =new TypeCAndOmtpAdapter();
       erji.omtpIo();
    }

到这里,我们就可以使用适配器调用我们期望的方法了,可以使用我们现有的逻辑。相当于我们用typec接口接上了圆孔的耳机。

但是如果我们的typc也不同呢,一个使安卓的,一个是苹果的,我们要求这个连接线都可以连,怎么办呢,我们把适配器改一下。

public class TypeCAndOmtpAdapter implements Omtp{

    private TypeC typeC;

    public TypeCAndOmtpAdapter(TypeC typeC) {
        this.typeC = typeC;
    }

    @Override
    public void omtpIo() {//改写目标接口,接上现有类的接口
        System.out.println("可以链接typec的omtp接口");
        typeC.typcIO();
    }
}

把typc定义为接口,另外创建两个实现类

public class TypeCApple implements TypeC{

    @Override
    public void typcIO() {
        System.out.println("苹果的接口");
    }
}
public class TypeCAndriod implements TypeC{

    @Override
    public void typcIO() {
        System.out.println("安卓的接口");
    }
}

我们把适配器升级了,使用构造方法把我们现有的类传进来,再使用也可以。

以上三个例子其实就是适配器模式的三种类型,第一个是接口适配器,第二个是类适配器,第三个是对象适配器,后两个其实是一种,只是实现手法有一些区别。

 

适配器模式和装饰模式的区别:

从适配器的对象适配器来看,和装饰模式的实现手法很像。但是他们的目标是有区别的

装饰模式:目标和自定义装饰类实现的是同一个接口,拥有的行为和目标类一样,只是要改写目标类某些方法,变成自己的方法,完成包装。

适配器模式:目标和现存类或接口并不一致,也不是同一个类型,适配器只是在中间转换,把两者都拿过来,使两者合作,完成转换。

4.工厂模式

工厂模式,顾名思义就是生成东西的地方,在Java中就是生产类的地方,这是创建型模式,往往是当你的某些对象要分门别类,但是又相互关联,在创建的时候经常需要做出不同的选择,为了降低耦合,我们应该尽量抽取创建的行为,集中到工厂中,于是就有了工厂模式。

1.简单工厂

简单工厂很简单,就是最常用的抽取。还用猫狗动物举例,实例化一个猫或者狗类,平时用new,抽取后将new的工作集合到工厂中

public class AnimalFactory {
    public static Animal getAnimal(String type){
        Animal a =null;
        if("Cat".equals(type)){
            a= new Cat();
        }else if("Dog".equals(type)){
            a= new Dog();
        }
        return a;
    }
}

使用:

 public static void main(String[] args) throws Exception {
        Animal cat = AnimalFactory.getAnimal("Cat");
        cat.eat();
    }

这种方式将new Cat和new Dog抽取出来,优点是清楚简单,代码量少,缺点是必须拥有修改工厂类源码的权限,开发我们自己编写的工厂一般是这样的。

2.工厂方法模式

如果我们不能修改工厂源码怎么办呢,这时工厂的设计就需要向外扩展,利用java多态的特性,对工厂方法进行扩展,创建猫工厂和狗工厂,并重写总工厂的方法。

public interface AnimalFactory {
   public Animal getAnimal();
}
public class CatFactory implements AnimalFactory {
    @Override
    public Animal getAnimal() {
        return new Cat();
    }
}
public class DogFactory implements AnimalFactory {
    @Override
    public Animal getAnimal() {
        return new Dog();
    }
}

使用:

 public static void main(String[] args) throws Exception {
        AnimalFactory factory =new DogFactory();
        Animal dog = factory.getAnimal();
        dog.eat();
    }

这种方法就可以不改AnimalFactory,但是每次增加一个新类就需要同时增加一个新的具体工厂。比如想增加一个pig,就需要写一个pig工厂。

优点是对外扩展方便,不需改源码。

缺点是代码量大,比较麻烦。

图例;

3.抽象工厂模式

以上两种工厂都是创建一种动物,比如狗,猫,猪等。那么如果我想创建白猫白狗,黑猫黑狗呢,或者除了创建猫狗,还创建鸡鸭呢。猫狗属于一类,鸡鸭属于另一类,但是都是动物,按照前面的方式应该是两个不同的工厂,宠物工厂和家禽工厂,但他们又都是动物,所以应该都属于动物工厂,所以抽象工厂模式就是"工厂的工厂"模式。

假如我现在有两个简单工厂模式,PetFactory(宠物工厂)和PoultryFactory(家禽工厂),怎么把他们抽取到一个AnimalFactory中呢,我们可以使用工厂方法模式的形式,让两个工厂继承一个抽象工厂AnimalFactory,重写其中的方法。

PetFactory工厂和相关类:

public class PetFactory  extends AnimalFactory{
    public Pet getPet(String type){
        Pet p =null;
        if("cat".equals(type)){
            p =new Cat();
        }else {
            p =new Dog();
        }
        return p;
    }

    @Override
    public Poultry getPoultry(String type) {
        return null;
    }
}
public interface Pet {
    public  void eat();
}
public class Cat implements Pet {
    @Override
    public void eat() {
        System.out.println("猫的吃方法");
    }
}
public class Dog implements Pet{
    @Override
    public void eat() {
        System.out.println("狗的吃方法");
    }
}

 PoultryFactory工厂和相关类

public class PoultryFactory  extends AnimalFactory{

    public Poultry getPoultry(String type){
        Poultry poultry =null;
        if("chicken".equals(type)){
            poultry =new Chicken();
        }else {
            poultry =new Duck();
        }
        return poultry;
    }

    @Override
    public Pet getPet(String type) {
        return null;
    }

}
public interface Poultry {
    void eat();
}
public class Chicken implements Poultry {
    @Override
    public void eat() {
        System.out.println("小鸡吃米");
    }
}
public class Duck implements Poultry{
    @Override
    public void eat() {
        System.out.println("鸭子会游泳");
    }
}

者两个工厂都继承了AnimalFactory

public abstract class AnimalFactory {
    public abstract Pet getPet(String type);
    public abstract Poultry getPoultry(String type);
}

到这里我们已经完成了抽象工厂,可以使用工厂方法模式那样的创建方式使用AnimalFactory,但按照惯例一般会再创建一个工厂提供者,将创建具体工厂的操作再用简单工厂模式的形式包装起来。提供工厂的工厂类

public class FactoryProducer {
    public AnimalFactory getAnimalFactory(String type){
        if("pet".equals(type)){
            return new PetFactory();
        }else if("poultry".equals(type)){
            return new PoultryFactory();
        }
        return null;
    }
}

使用;

public static void main(String[] args) throws Exception {
        AnimalFactory f = FactoryProducer.getAnimalFactory("poultry");
        Poultry duck = f.getPoultry("duck");
        duck.eat();
    }

这种工厂模式比较复杂,但其实也是基于简单工厂和工厂方法模式的结合,进一步进行抽取。

图例:

5.单例模式

单例模式用的地方很多,所谓单例就是一个实例,那么要达到这个目的,我们平时的代码中就有一种简单方式,比如在一个类中定义一个static静态成员变量,这样就可以实现共享的目的,也就是所有对象都共享这一个变量。

单例模式也是同样的原理,但是为了让一个类只有一个对象,并且被所有对象共享,除了被静态,还有一点是不能被随便实例化,只能被实例化一次,这里有一个关键点:私有化构造方法,只有构造方法私有化后,别人就不能new了。剩下的就是创建方式,有几种 创建方式。

1.饿汉式

public class SingleObj {
    private SingleObj() { }//构造方法私有化,非常关键
    
    private static  SingleObj singleObj =new SingleObj();//定义一个静态对象,并直接实例化
    
    public  static SingleObj getInStance(){//通过公共方法对外提供我们实例化的对象。
        return singleObj;
    }
}

这种方式最常用,也比较简单,在java中Runtime类就是用的这种方式,这种方式缺点就是占一定的内存,尤其是你的对象很大的话,因为一上来就要实例化一个对象,占空间。但是以现在的电脑配置来讲如果需要单例模式的地方不多的情况下,无伤大雅,所以用的很多。

2.懒汉式

public class SingleObj {
    private SingleObj() { }//构造方法私有化,非常关键

    private static  SingleObj singleObj ;//定义一个静态变量,且不给实例对象,默认为null

    public  static synchronized SingleObj getInStance(){//通过公共方法对外提供我们实例化的对象。
        if(singleObj==null){
            return singleObj;
        }
       return singleObj;
    }
}

懒汉式的“懒”取自“lazy loading”的lazy,也就是懒加载,懒加载就是用的时候再实例化,这样可以解决一上来就实例化占用空间的问题,但是getInStance方法在被多线程调用的时候有同时访问到singleObj为null的情况,所以该方法需要加上synchronized关键字,但是这样一来,多线程情况下性能就受到了影响。这也是其缺点。

这两种方式就是最常用的两种基本形式。除了这两种,还有很多其他的实现方式,比如双检索方式、静态内部类式(登记式)、枚举式等。可以参考其他博客。

某大神的博客

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来为您简单介绍几种常用的Java设计模式,并附上示例代码。 1. 工厂模式(Factory Pattern) 定义:工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,而无需向客户端暴露创建逻辑,并且是通过使用一个公共接口来指向新创建的对象。 示例代码:假设我们有一个形状(Shape)接口,有三个不同的实现:圆形(Circle)、矩形(Rectangle)和正方形(Square)。我们可以使用工厂模式创建这些形状。 ``` public interface Shape { void draw(); } public class Circle implements Shape { @Override public void draw() { System.out.println("Drawing Circle"); } } public class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing Rectangle"); } } public class Square implements Shape { @Override public void draw() { System.out.println("Drawing Square"); } } public class ShapeFactory { public Shape getShape(String shapeType) { if (shapeType == null) { return null; } if (shapeType.equalsIgnoreCase("CIRCLE")) { return new Circle(); } else if (shapeType.equalsIgnoreCase("RECTANGLE")) { return new Rectangle(); } else if (shapeType.equalsIgnoreCase("SQUARE")) { return new Square(); } return null; } } ``` 我们可以使用ShapeFactory类来获取不同类型的形状对象: ``` ShapeFactory shapeFactory = new ShapeFactory(); Shape circle = shapeFactory.getShape("CIRCLE"); circle.draw(); Shape rectangle = shapeFactory.getShape("RECTANGLE"); rectangle.draw(); Shape square = shapeFactory.getShape("SQUARE"); square.draw(); ``` 2. 单例模式(Singleton Pattern) 定义:单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。 示例代码:假设我们有一个Settings类,用于存储应用程序的设置信息。我们可以使用单例模式确保只有一个Settings实例,以便在整个应用程序中共享设置。 ``` public class Settings { private static Settings instance = new Settings(); private Settings() {} public static Settings getInstance() { return instance; } public void setSetting(String key, String value) { // ... } public String getSetting(String key) { // ... return null; } } ``` 我们可以通过Settings.getInstance()方法获取Settings的唯一实例: ``` Settings settings = Settings.getInstance(); settings.setSetting("fontSize", "14"); String fontSize = settings.getSetting("fontSize"); ``` 3. 观察者模式(Observer Pattern) 定义:观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有观察者都会收到通知并更新自己的状态。 示例代码:假设我们有一个Subject接口和两个实现:WeatherData和StockData,它们都维护着一些数据。我们可以使用观察者模式来让多个观察者监听这些主题对象的变化。 ``` public interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers(); } public interface Observer { void update(float temperature, float humidity, float pressure); } public class WeatherData implements Subject { private List<Observer> observers = new ArrayList<>(); private float temperature; private float humidity; private float pressure; @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { observers.remove(o); } @Override public void notifyObservers() { for (Observer o : observers) { o.update(temperature, humidity, pressure); } } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } private void measurementsChanged() { notifyObservers(); } } public class StockData implements Subject { private List<Observer> observers = new ArrayList<>(); private String symbol; private float price; @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { observers.remove(o); } @Override public void notifyObservers() { for (Observer o : observers) { o.update(price); } } public void setPrice(float price) { this.price = price; priceChanged(); } private void priceChanged() { notifyObservers(); } } public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } private void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } public class StockPriceDisplay implements Observer { private float price; @Override public void update(float price) { this.price = price; display(); } private void display() { System.out.println("Stock price: $" + price); } } ``` 我们可以创建一个WeatherData对象和一个StockData对象,并向它们注册两个观察者:CurrentConditionsDisplay和StockPriceDisplay。当WeatherData或StockData对象中的数据发生变化时,它们会通知它们的观察者。 ``` WeatherData weatherData = new WeatherData(); StockData stockData = new StockData(); CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(); StockPriceDisplay stockPriceDisplay = new StockPriceDisplay(); weatherData.registerObserver(currentConditionsDisplay); stockData.registerObserver(stockPriceDisplay); weatherData.setMeasurements(80, 65, 30.4f); stockData.setPrice(100); ``` 这就是Java中的三种常用设计模式简单示例。希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值