设计模式系列 - 结构型模式

结构设计模式向您展示了如何以灵活和可扩展的方式将系统的不同部分粘合在一起。它们可以帮助您保证当其中一个部分发生更改时,整个结构不需要更改。
这些模式关注的是类之间如何相互继承,以及它们是如何由其他类组成的。结构模式使用继承来组合接口或实现。

适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。

//步骤 1
//为媒体播放器和更高级的媒体播放器创建接口。

//MediaPlayer.java
public interface MediaPlayer {
   public void play(String audioType, String fileName);
}
AdvancedMediaPlayer.java
public interface AdvancedMediaPlayer { 
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}
//步骤 2
//创建实现了 AdvancedMediaPlayer 接口的实体类。

//VlcPlayer.java
public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);      
   }
 
   @Override
   public void playMp4(String fileName) {
      //什么也不做
   }
}
//Mp4Player.java
public class Mp4Player implements AdvancedMediaPlayer{
 
   @Override
   public void playVlc(String fileName) {
      //什么也不做
   }
 
   @Override
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);      
   }
}
//步骤 3
//创建实现了 MediaPlayer 接口的适配器类。

//MediaAdapter.java
public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}
//步骤 4
//创建实现了 MediaPlayer 接口的实体类。

//AudioPlayer.java
public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 
 
   @Override
   public void play(String audioType, String fileName) {    
 
      //播放 mp3 音乐文件的内置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);         
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}
//步骤 5
//使用 AudioPlayer 来播放不同类型的音频格式。

//AdapterPatternDemo.java
public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();
 
      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}
步骤 6
执行程序,输出结果:

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported

 

桥接模式

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
桥设计模式用于将一个类分解为两个部分——抽象和它的实现——以便这两个部分在将来都能在不影响彼此的情况下发展。它增加了类抽象和它的实现之间的松散耦合。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

当您必须以相互正交的方式对不同时间进行子类化时,它变得很方便。
例如,假设您正在创建具有不同颜色的各种图形用户界面形状。一种解决方案可能是:

但上述解决方案存在问题。如果您想更改Rectange类,那么您也可能最终更改BlueRectangle和RedRectangle,即使更改是颜色特定的,那么您也可能需要更改Circle类。
您可以通过以下方式分离形状和颜色接口来解决上述问题。

 

//首先是形状类:该类为一个抽象类,主要提供画形状的方法 Shape.java :
public abstract class Shape {
    Color color;
 
    public void setColor(Color color) {
        this.color = color;
    }
    
    public abstract void draw();
}
//然后是三个形状 。
//圆形 Circle.java :
public class Circle extends Shape{
 
    public void draw() {
        color.bepaint("正方形");
    }
}
//长方形 Rectangle.java :
public class Rectangle extends Shape{
 
    public void draw() {
        color.bepaint("长方形");
    }
 
}
//正方形 Square.java :
public class Square extends Shape{
 
    public void draw() {
        color.bepaint("正方形");
    }
 
}
//颜色接口 Color.java :
public interface Color {
    public void bepaint(String shape);
}
//白色 White.java :
public class White implements Color{
 
    public void bepaint(String shape) {
        System.out.println("白色的" + shape);
    }
 
}
//灰色 Gray.java :
public class Gray implements Color{
 
    public void bepaint(String shape) {
        System.out.println("灰色的" + shape);
    }
}
//黑色 Black.java :
public class Black implements Color{
 
    public void bepaint(String shape) {
        System.out.println("黑色的" + shape);
    }
}
//客户端 Client.java :
public class Client {
    public static void main(String[] args) {
        //白色
        Color white = new White();
        //正方形
        Shape square = new Square();
        //白色的正方形
        square.setColor(white);
        square.draw();
        
        //长方形
        Shape rectange = new Rectangle();
        rectange.setColor(white);
        rectange.draw();
    }
}
运行结果:

白色的正方形
白色的长方形

 

组合模式

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。
组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。复合设计模式是一种修改对象结构的结构模式。这种模式最适合于需要处理形成树状层次结构的对象的情况。在该树中,每个节点/对象(根节点除外)都是复合节点或叶节点。实现复合模式允许客户机统一地处理单个对象和组合。

import java.util.ArrayList; 
import java.util.List; 
  
  
// A common interface for all employee 
interface Employee 
{ 
    public void showEmployeeDetails(); 
} 
  
class Developer implements Employee 
{ 
    private String name; 
    private long empId; 
    private String position; 
      
    public Developer(long empId, String name, String position) 
    { 
        // Assign the Employee id, 
        // name and the position 
        this.empId = empId; 
        this.name = name; 
        this.position = position; 
    } 
      
    @Override
    public void showEmployeeDetails()  
    { 
        System.out.println(empId+" " +name+ " " + position ); 
    } 
} 
  
class Manager implements Employee 
{ 
    private String name; 
    private long empId; 
    private String position; 
   
    public Manager(long empId, String name, String position) 
    { 
        this.empId = empId; 
        this.name = name; 
        this.position = position; 
    } 
       
    @Override
    public void showEmployeeDetails()  
    { 
        System.out.println(empId+" " +name+ " " + position ); 
    } 
} 
  
  
// Class used to get Employee List 
// and do the opertions like  
// add or remove Employee 
  
class CompanyDirectory implements Employee 
{ 
    private List<Employee> employeeList = new ArrayList<Employee>(); 
        
    @Override
    public void showEmployeeDetails()  
    { 
        for(Employee emp:employeeList) 
        { 
            emp.showEmployeeDetails(); 
        } 
    } 
        
    public void addEmployee(Employee emp) 
    { 
        employeeList.add(emp); 
    } 
        
    public void removeEmployee(Employee emp) 
    { 
        employeeList.remove(emp); 
    } 
} 
  
// Driver class 
public class Company 
{ 
    public static void main (String[] args) 
    { 
        Developer dev1 = new Developer(100, "Lokesh Sharma", "Pro Developer"); 
        Developer dev2 = new Developer(101, "Vinay Sharma", "Developer"); 
        CompanyDirectory engDirectory = new CompanyDirectory(); 
        engDirectory.addEmployee(dev1); 
        engDirectory.addEmployee(dev2); 
           
        Manager man1 = new Manager(200, "Kushagra Garg", "SEO Manager"); 
        Manager man2 = new Manager(201, "Vikram Sharma ", "Kushagra's Manager"); 
           
        CompanyDirectory accDirectory = new CompanyDirectory(); 
        accDirectory.addEmployee(man1); 
        accDirectory.addEmployee(man2); 
       
        CompanyDirectory directory = new CompanyDirectory(); 
        directory.addEmployee(engDirectory); 
        directory.addEmployee(accDirectory); 
        directory.showEmployeeDetails(); 
    } 
} 
Output :

100 Lokesh Sharma Pro Developer
101 Vinay Sharma Developer
200 Kushagra Garg SEO Manager
201 Vikram Sharma  Kushagra's Manager

 

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

// Abstract Pizza class (All classes extend 
// from this) 
abstract class Pizza 
{ 
    // it is an abstract pizza 
    String description = "Unkknown Pizza"; 
  
    public String getDescription() 
    { 
        return description; 
    } 
  
    public abstract int getCost(); 
} 
  
// The decorator class :  It extends Pizza to be 
// interchangable with it topings decorator can 
// also be implemented as an interface 
abstract class ToppingsDecorator extends Pizza 
{ 
    public abstract String getDescription(); 
} 
  
// Concrete pizza classes 
class PeppyPaneer extends Pizza 
{ 
    public PeppyPaneer() { description = "PeppyPaneer"; } 
    public int getCost() {  return 100; } 
} 
class FarmHouse extends Pizza 
{ 
    public FarmHouse() {  description = "FarmHouse"; } 
    public int getCost() { return 200; } 
} 
class Margherita extends Pizza 
{ 
    public Margherita()  { description = "Margherita"; } 
    public int getCost() { return 100;  } 
} 
class ChickenFiesta extends Pizza 
{ 
    public ChickenFiesta() { description = "ChickenFiesta";} 
    public int getCost() { return 200; } 
} 
class SimplePizza extends Pizza 
{ 
public SimplePizza() { description = "SimplePizza"; } 
public int getCost() {  return 50;  } 
} 
  
// Concrete toppings classes 
class FreshTomato extends ToppingsDecorator 
{ 
    // we need a reference to obj we are decorating 
    Pizza pizza; 
  
    public FreshTomato(Pizza pizza) { this.pizza = pizza; } 
    public String getDescription() { 
        return pizza.getDescription() + ", Fresh Tomato "; 
    } 
    public int getCost() { return 40 + pizza.getCost(); } 
} 
class Barbeque extends ToppingsDecorator 
{ 
    Pizza pizza; 
    public Barbeque(Pizza pizza) {  this.pizza = pizza;  } 
    public String getDescription() { 
        return pizza.getDescription() + ", Barbeque "; 
    } 
    public int getCost() { return 90 + pizza.getCost(); } 
} 
class Paneer extends ToppingsDecorator 
{ 
    Pizza pizza; 
    public Paneer(Pizza pizza)  {  this.pizza = pizza; } 
    public String getDescription() { 
        return pizza.getDescription() + ", Paneer "; 
    } 
    public int getCost()  {  return 70 + pizza.getCost(); } 
} 
  
// Other toppings can be coded in a similar way 
// Driver class and method 
class PizzaStore 
{ 
    public static void main(String args[]) 
    { 
        // create new margherita pizza 
        Pizza pizza = new Margherita(); 
        System.out.println( pizza.getDescription() + 
                         " Cost :" + pizza.getCost()); 
  
        // create new FarmHouse pizza 
        Pizza pizza2 = new FarmHouse(); 
  
        // decorate it with freshtomato topping 
        pizza2 = new FreshTomato(pizza2); 
  
        //decorate it with paneer topping 
        pizza2 = new Paneer(pizza2); 
  
        System.out.println( pizza2.getDescription() + 
                         " Cost :" + pizza2.getCost()); 
        Pizza pizza3 = new Barbeque(null);    //no specific pizza 
        System.out.println( pizza3.getDescription() + "  Cost :" + pizza3.getCost()); 
   } 
} 
Output:

Margherita Cost :100
FarmHouse, Fresh Tomato , Paneer Cost :310

 

外观模式

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
关键代码:在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。

//步骤 1
//创建一个接口。
//Shape.java
public interface Shape {
   void draw();
}
//步骤 2
//创建实现接口的实体类。
Rectangle.java
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Rectangle::draw()");
   }
}
Square.java
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Square::draw()");
   }
}
Circle.java
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Circle::draw()");
   }
}
//步骤 3
//创建一个外观类。
ShapeMaker.java
public class ShapeMaker {
   private Shape circle;
   private Shape rectangle;
   private Shape square;
 
   public ShapeMaker() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Square();
   }
 
   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }
   public void drawSquare(){
      square.draw();
   }
}
//步骤 4
//使用该外观类画出各种类型的形状。
FacadePatternDemo.java
public class FacadePatternDemo {
   public static void main(String[] args) {
      ShapeMaker shapeMaker = new ShapeMaker();
 
      shapeMaker.drawCircle();
      shapeMaker.drawRectangle();
      shapeMaker.drawSquare();      
   }
}
//步骤 5
//执行程序,输出结果:

Circle::draw()
Rectangle::draw()
Square::draw()


享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

 

Pen.java
public interface Pen 
{   
    public void setColor(String color);
    public void draw(String content); 
}
BrushSize.java
public enum BrushSize {
    THIN, MEDIUM, THICK
}
ThickPen.java
public class ThickPen implements Pen {
     
    final BrushSize brushSize = BrushSize.THICK;    //intrinsic state - shareable
    private String color = null;                    //extrinsic state - supplied by client
     
    public void setColor(String color) {
        this.color = color;
    }
 
    @Override
    public void draw(String content) {
        System.out.println("Drawing THICK content in color : " + color);
    }
}
ThinPen.java
public class ThinPen implements Pen {
     
    final BrushSize brushSize = BrushSize.THIN;
    private String color = null; 
     
    public void setColor(String color) {
        this.color = color;
    }
 
    @Override
    public void draw(String content) {
        System.out.println("Drawing THIN content in color : " + color);
    }
}
MediumPen.java
public class MediumPen implements Pen {
     
    final BrushSize brushSize = BrushSize.MEDIUM;
    private String color = null; 
     
    public void setColor(String color) {
        this.color = color;
    }
 
    @Override
    public void draw(String content) {
        System.out.println("Drawing MEDIUM content in color : " + color);
    }
}


PenFactory.java
import java.util.HashMap;
 
public class PenFactory 
{
    private static final HashMap<String, Pen> pensMap = new HashMap<>();
 
    public static Pen getThickPen(String color) 
    {
        String key = color + "-THICK";
         
        Pen pen = pensMap.get(key);
         
        if(pen != null) {
            return pen;
        } else {
            pen = new ThickPen();
            pen.setColor(color);
            pensMap.put(key, pen);
        }
         
        return pen;
    }
     
    public static Pen getThinPen(String color) 
    {
        String key = color + "-THIN";
         
        Pen pen = pensMap.get(key);
         
        if(pen != null) {
            return pen;
        } else {
            pen = new ThinPen();
            pen.setColor(color);
            pensMap.put(key, pen);
        }
         
        return pen;
    }
     
    public static Pen getMediumPen(String color) 
    {
        String key = color + "-MEDIUM";
         
        Pen pen = pensMap.get(key);
         
        if(pen != null) {
            return pen;
        } else {
            pen = new MediumPen();
            pen.setColor(color);
            pensMap.put(key, pen);
        }
         
        return pen;
    }
}

PaintBrushClient.java
public class PaintBrushClient 
{
    public static void main(String[] args) 
    {
        Pen yellowThinPen1 = PenFactory.getThickPen("YELLOW");  //created new pen
        yellowThinPen1.draw("Hello World !!");
         
        Pen yellowThinPen2 = PenFactory.getThickPen("YELLOW");  //pen is shared
        yellowThinPen2.draw("Hello World !!");
         
        Pen blueThinPen = PenFactory.getThickPen("BLUE");       //created new pen
        blueThinPen.draw("Hello World !!");
         
        System.out.println(yellowThinPen1.hashCode());
        System.out.println(yellowThinPen2.hashCode());
         
        System.out.println(blueThinPen.hashCode());
    }
}
Program output.

Console
Drawing THICK content in color : YELLOW
Drawing THICK content in color : YELLOW
Drawing THICK content in color : BLUE
 
2018699554      //same object
2018699554      //same object
1311053135

 

代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
代理对象为另一个对象提供代理项或占位符以控制对它的访问。代理基本上是对我们创建的预期对象的替代,因为许多原因,例如安全原因或创建完全初始化的原始对象的相关成本。
何时使用代理设计模式?
代理对象隐藏原始对象并控制对其的访问。当我们想使用一个可以作为其他对象接口的类时,我们可以使用代理。
代理被大量用于实现延迟加载相关的用例,在这些用例中,我们不希望在实际需要之前创建完整的对象。
代理也可以用于在原始对象周围添加附加的安全层。

RealObject.java
public interface RealObject 
{
    public void doSomething();
}
RealObjectImpl.java
public class RealObjectImpl implements RealObject {
 
    @Override
    public void doSomething() {
        System.out.println("Performing work in real object");
    }
 
}
RealObjectProxy.java
public class RealObjectProxy extends RealObjectImpl 
{
    @Override
    public void doSomething() 
    {
        //Perform additional logic and security
        //Even we can block the operation execution
        System.out.println("Delegating work on real object");
        super.doSomething();
    }
}
Client.java
public class Client 
{
    public static void main(String[] args) 
    {
        RealObject proxy = new RealObjectProxy();
        proxy.doSomething();
    }
}
Program output.

Console
Delegating work on real object
Performing work in real object

 

posted @ 2020-03-31 17:11  昕友软件开发  阅读(365)  评论(0编辑  收藏  举报
欢迎访问我的开源项目:xyIM企业即时通讯