// 装饰可以改变组件接口所定义的操作。 interface DataSource is method writeData(data) method readData():data
// 具体组件提供操作的默认实现。这些类在程序中可能会有几个变体。 class FileDataSource implements DataSource is constructorFileDataSource(filename){ ... } methodwriteData(data)is // 将数据写入文件。 methodreadData():data is // 从文件读取数据。
// 装饰基类和其他组件遵循相同的接口。该类的主要任务是定义所有具体装饰的封 // 装接口。封装的默认实现代码中可能会包含一个保存被封装组件的成员变量,并 // 且负责对其进行初始化。 class DataSourceDecorator implements DataSource is protected field wrappee: DataSource
// 选项 1:装饰组件的简单示例 class Application is method dumbUsageExample() is source = new FileDataSource("somefile.dat") source.writeData(salaryRecords) // 已将明码数据写入目标文件。
source = new CompressionDecorator(source) source.writeData(salaryRecords) // 已将压缩数据写入目标文件。
namespaceRefactoringGuru.DesignPatterns.Composite.Conceptual { // The base Component interface defines operations that can be altered by // decorators. publicabstractclassComponent { publicabstractstringOperation(); }
// Concrete Components provide default implementations of the operations. // There might be several variations of these classes. classConcreteComponent : Component { publicoverridestringOperation() { return"ConcreteComponent"; } }
// The base Decorator class follows the same interface as the other // components. The primary purpose of this class is to define the wrapping // interface for all concrete decorators. The default implementation of the // wrapping code might include a field for storing a wrapped component and // the means to initialize it. abstractclassDecorator : Component { protected Component _component;
// The Decorator delegates all work to the wrapped component. publicoverridestringOperation() { if (this._component != null) { returnthis._component.Operation(); } else { returnstring.Empty; } } }
// Concrete Decorators call the wrapped object and alter its result in some // way. classConcreteDecoratorA : Decorator { publicConcreteDecoratorA(Component comp) : base(comp) { }
// Decorators may call parent implementation of the operation, instead // of calling the wrapped object directly. This approach simplifies // extension of decorator classes. publicoverridestringOperation() { return$"ConcreteDecoratorA({base.Operation()})"; } }
// Decorators can execute their behavior either before or after the call to // a wrapped object. classConcreteDecoratorB : Decorator { publicConcreteDecoratorB(Component comp) : base(comp) { }
publicoverridestringOperation() { return$"ConcreteDecoratorB({base.Operation()})"; } } publicclassClient { // The client code works with all objects using the Component interface. // This way it can stay independent of the concrete classes of // components it works with. publicvoidClientCode(Component component) { Console.WriteLine("RESULT: " + component.Operation()); } } classProgram { staticvoidMain(string[] args) { Client client = new Client();
var simple = new ConcreteComponent(); Console.WriteLine("Client: I get a simple component:"); client.ClientCode(simple); Console.WriteLine();
// ...as well as decorated ones. // // Note how decorators can wrap not only simple components but the // other decorators as well. ConcreteDecoratorA decorator1 = new ConcreteDecoratorA(simple); ConcreteDecoratorB decorator2 = new ConcreteDecoratorB(decorator1); Console.WriteLine("Client: Now I've got a decorated component:"); client.ClientCode(decorator2); } } }
Output.txt: 执行结果
1 2 3 4 5
Client: I get a simple component: RESULT: ConcreteComponent
Client: Now I've got a decorated component: RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
/** * The base Component interface defines operations that can be altered by * decorators. */ classComponent { public: virtual ~Component() {} virtual std::string Operation()const= 0; }; /** * Concrete Components provide default implementations of the operations. There * might be several variations of these classes. */ classConcreteComponent : public Component { public: std::string Operation()constoverride{ return"ConcreteComponent"; } }; /** * The base Decorator class follows the same interface as the other components. * The primary purpose of this class is to define the wrapping interface for all * concrete decorators. The default implementation of the wrapping code might * include a field for storing a wrapped component and the means to initialize * it. */ classDecorator : public Component { /** * @var Component */ protected: Component* component_;
public: Decorator(Component* component) : component_(component) { } /** * The Decorator delegates all work to the wrapped component. */ std::string Operation()constoverride{ returnthis->component_->Operation(); } }; /** * Concrete Decorators call the wrapped object and alter its result in some way. */ classConcreteDecoratorA : public Decorator { /** * Decorators may call parent implementation of the operation, instead of * calling the wrapped object directly. This approach simplifies extension of * decorator classes. */ public: ConcreteDecoratorA(Component* component) : Decorator(component) { } std::string Operation()constoverride{ return"ConcreteDecoratorA(" + Decorator::Operation() + ")"; } }; /** * Decorators can execute their behavior either before or after the call to a * wrapped object. */ classConcreteDecoratorB : public Decorator { public: ConcreteDecoratorB(Component* component) : Decorator(component) { }
std::string Operation()constoverride{ return"ConcreteDecoratorB(" + Decorator::Operation() + ")"; } }; /** * The client code works with all objects using the Component interface. This * way it can stay independent of the concrete classes of components it works * with. */ voidClientCode(Component* component){ // ... std::cout << "RESULT: " << component->Operation(); // ... }
intmain(){ /** * This way the client code can support both simple components... */ Component* simple = new ConcreteComponent; std::cout << "Client: I've got a simple component:\n"; ClientCode(simple); std::cout << "\n\n"; /** * ...as well as decorated ones. * * Note how decorators can wrap not only simple components but the other * decorators as well. */ Component* decorator1 = newConcreteDecoratorA(simple); Component* decorator2 = newConcreteDecoratorB(decorator1); std::cout << "Client: Now I've got a decorated component:\n"; ClientCode(decorator2); std::cout << "\n";
- Input ---------------- Name,Salary John Smith,100000 Steven Jobs,912000 - Encoded -------------- Zkt7e1Q5eU8yUm1Qe0ZsdHJ2VXp6dDBKVnhrUHtUe0sxRUYxQkJIdjVLTVZ0dVI5Q2IwOXFISmVUMU5rcENCQmdxRlByaD4+ - Decoded -------------- Name,Salary John Smith,100000 Steven Jobs,912000
/** * The base Component interface defines operations that can be altered by * decorators. */ interfaceComponent { publicfunctionoperation(): string; }
/** * Concrete Components provide default implementations of the operations. There * might be several variations of these classes. */ classConcreteComponentimplementsComponent { publicfunctionoperation(): string { return"ConcreteComponent"; } }
/** * The base Decorator class follows the same interface as the other components. * The primary purpose of this class is to define the wrapping interface for all * concrete decorators. The default implementation of the wrapping code might * include a field for storing a wrapped component and the means to initialize * it. */ classDecoratorimplementsComponent { /** * @var Component */ protected$component;
/** * The Decorator delegates all work to the wrapped component. */ publicfunctionoperation(): string { return$this->component->operation(); } }
/** * Concrete Decorators call the wrapped object and alter its result in some way. */ classConcreteDecoratorAextendsDecorator { /** * Decorators may call parent implementation of the operation, instead of * calling the wrapped object directly. This approach simplifies extension * of decorator classes. */ publicfunctionoperation(): string { return"ConcreteDecoratorA(" . parent::operation() . ")"; } }
/** * Decorators can execute their behavior either before or after the call to a * wrapped object. */ classConcreteDecoratorBextendsDecorator { publicfunctionoperation(): string { return"ConcreteDecoratorB(" . parent::operation() . ")"; } }
/** * The client code works with all objects using the Component interface. This * way it can stay independent of the concrete classes of components it works * with. */ functionclientCode(Component $component) { // ...
echo"RESULT: " . $component->operation();
// ... }
/** * This way the client code can support both simple components... */ $simple = newConcreteComponent(); echo"Client: I've got a simple component:\n"; clientCode($simple); echo"\n\n";
/** * ...as well as decorated ones. * * Note how decorators can wrap not only simple components but the other * decorators as well. */ $decorator1 = newConcreteDecoratorA($simple); $decorator2 = newConcreteDecoratorB($decorator1); echo"Client: Now I've got a decorated component:\n"; clientCode($decorator2);
Output.txt: 执行结果
1 2 3 4 5
Client: I've got a simple component: RESULT: ConcreteComponent
Client: Now I've got a decorated component: RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
/** * The Component interface declares a filtering method that must be implemented * by all concrete components and decorators. */ interfaceInputFormat { publicfunctionformatText(string$text): string; }
/** * The Concrete Component is a core element of decoration. It contains the * original text, as is, without any filtering or formatting. */ classTextInputimplementsInputFormat { publicfunctionformatText(string$text): string { return$text; } }
/** * The base Decorator class doesn't contain any real filtering or formatting * logic. Its main purpose is to implement the basic decoration infrastructure: * a field for storing a wrapped component or another decorator and the basic * formatting method that delegates the work to the wrapped object. The real * formatting job is done by subclasses. */ classTextFormatimplementsInputFormat { /** * @var InputFormat */ protected$inputFormat;
/** * Decorator delegates all work to a wrapped component. */ publicfunctionformatText(string$text): string { return$this->inputFormat->formatText($text); } }
/** * This Concrete Decorator strips out all HTML tags from the given text. */ classPlainTextFilterextendsTextFormat { publicfunctionformatText(string$text): string { $text = parent::formatText($text); returnstrip_tags($text); } }
/** * This Concrete Decorator strips only dangerous HTML tags and attributes that * may lead to an XSS vulnerability. */ classDangerousHTMLTagsFilterextendsTextFormat { private$dangerousTagPatterns = [ "|<script.*?>([\s\S]*)?</script>|i", // ... ];
/** * The client code might be a part of a real website, which renders user- * generated content. Since it works with formatters through the Component * interface, it doesn't care whether it gets a simple component object or a * decorated one. */ functiondisplayCommentAsAWebsite(InputFormat $format, string$text) { // ..
echo$format->formatText($text);
// .. }
/** * Input formatters are very handy when dealing with user-generated content. * Displaying such content "as is" could be very dangerous, especially when * anonymous users can generate it (e.g. comments). Your website is not only * risking getting tons of spammy links but may also be exposed to XSS attacks. */ $dangerousComment = <<<HERE Hello! Nice blog post! Please visit my <a href='http://www.iwillhackyou.com'>homepage</a>. <script src="http://www.iwillhackyou.com/script.js"> performXSSAttack(); </script> HERE;
/** * Decorator allows stacking multiple input formats to get fine-grained control * over the rendered content. */ $dangerousForumPost = <<<HERE # Welcome This is my first post on this **gorgeous** forum. <script src="http://www.iwillhackyou.com/script.js"> performXSSAttack(); </script> HERE;
/** * Naive post rendering (unsafe, no formatting). */ $naiveInput = newTextInput(); echo"Website renders a forum post without filtering and formatting (unsafe, ugly):\n"; displayCommentAsAWebsite($naiveInput, $dangerousForumPost); echo"\n\n\n";
/** * Markdown formatter + filtering dangerous tags (safe, pretty). */ $text = newTextInput(); $markdown = newMarkdownFormat($text); $filteredInput = newDangerousHTMLTagsFilter($markdown); echo"Website renders a forum post after translating markdown markup" . " and filtering some dangerous HTML tags and attributes (safe, pretty):\n"; displayCommentAsAWebsite($filteredInput, $dangerousForumPost); echo"\n\n\n";
classComponent(): """ The base Component interface defines operations that can be altered by decorators. """
defoperation(self) -> str: pass
classConcreteComponent(Component): """ Concrete Components provide default implementations of the operations. There might be several variations of these classes. """
classDecorator(Component): """ The base Decorator class follows the same interface as the other components. The primary purpose of this class is to define the wrapping interface for all concrete decorators. The default implementation of the wrapping code might include a field for storing a wrapped component and the means to initialize it. """
classConcreteDecoratorA(Decorator): """ Concrete Decorators call the wrapped object and alter its result in some way. """
defoperation(self) -> str: """ Decorators may call parent implementation of the operation, instead of calling the wrapped object directly. This approach simplifies extension of decorator classes. """ returnf"ConcreteDecoratorA({self.component.operation()})"
classConcreteDecoratorB(Decorator): """ Decorators can execute their behavior either before or after the call to a wrapped object. """
defclient_code(component: Component) -> None: """ The client code works with all objects using the Component interface. This way it can stay independent of the concrete classes of components it works with. """
# ...
print(f"RESULT: {component.operation()}", end="")
# ...
if __name__ == "__main__": # This way the client code can support both simple components... simple = ConcreteComponent() print("Client: I've got a simple component:") client_code(simple) print("\n")
# ...as well as decorated ones. # # Note how decorators can wrap not only simple components but the other # decorators as well. decorator1 = ConcreteDecoratorA(simple) decorator2 = ConcreteDecoratorB(decorator1) print("Client: Now I've got a decorated component:") client_code(decorator2)
Output.txt: 执行结果
1 2 3 4 5
Client: I've got a simple component: RESULT: ConcreteComponent
Client: Now I've got a decorated component: RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
# The base Component interface defines operations that can be altered by # decorators. classComponent # @return [String] defoperation raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Concrete Components provide default implementations of the operations. There # might be several variations of these classes. classConcreteComponent < Component # @return [String] defoperation 'ConcreteComponent' end end
# The base Decorator class follows the same interface as the other components. # The primary purpose of this class is to define the wrapping interface for all # concrete decorators. The default implementation of the wrapping code might # include a field for storing a wrapped component and the means to initialize # it. classDecorator < Component attr_accessor:component
# @param [Component] component definitialize(component) @component = component end
# The Decorator delegates all work to the wrapped component. defoperation @component.operation end end
# Concrete Decorators call the wrapped object and alter its result in some way. classConcreteDecoratorA < Decorator # Decorators may call parent implementation of the operation, instead of # calling the wrapped object directly. This approach simplifies extension of # decorator classes. defoperation "ConcreteDecoratorA(#{@component.operation})" end end
# Decorators can execute their behavior either before or after the call to a # wrapped object. classConcreteDecoratorB < Decorator # @return [String] defoperation "ConcreteDecoratorB(#{@component.operation})" end end
# The client code works with all objects using the Component interface. This way # it can stay independent of the concrete classes of components it works with. defclient_code(component) # ...
print "RESULT: #{component.operation}"
# ... end
# This way the client code can support both simple components... simple = ConcreteComponent.new puts 'Client: I\'ve got a simple component:' client_code(simple) puts "\n\n"
# ...as well as decorated ones. # # Note how decorators can wrap not only simple components but the other # decorators as well. decorator1 = ConcreteDecoratorA.new(simple) decorator2 = ConcreteDecoratorB.new(decorator1) puts 'Client: Now I\'ve got a decorated component:' client_code(decorator2)
output.txt: 执行结果
1 2 3 4 5
Client: I've got a simple component: RESULT: ConcreteComponent
Client: Now I've got a decorated component: RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
/// The base Component interface defines operations that can be altered by /// decorators. protocolComponent {
funcoperation() -> String }
/// Concrete Components provide default implementations of the operations. There /// might be several variations of these classes. classConcreteComponent: Component {
/// The base Decorator class follows the same interface as the other components. /// The primary purpose of this class is to define the wrapping interface for /// all concrete decorators. The default implementation of the wrapping code /// might include a field for storing a wrapped component and the means to /// initialize it. classDecorator: Component {
/// The Decorator delegates all work to the wrapped component. funcoperation() -> String { return component.operation() } }
/// Concrete Decorators call the wrapped object and alter its result in some /// way. classConcreteDecoratorA: Decorator {
/// Decorators may call parent implementation of the operation, instead of /// calling the wrapped object directly. This approach simplifies extension /// of decorator classes. overridefuncoperation() -> String { return"ConcreteDecoratorA("+super.operation() +")" } }
/// Decorators can execute their behavior either before or after the call to a /// wrapped object. classConcreteDecoratorB: Decorator {
/// The client code works with all objects using the Component interface. This /// way it can stay independent of the concrete classes of components it works /// with. classClient { // ... staticfuncsomeClientCode(component: Component) { print("Result: "+ component.operation()) } // ... }
/// Let's see how it all works together. classDecoratorConceptual: XCTestCase {
functestDecoratorConceptual() { // This way the client code can support both simple components... print("Client: I've got a simple component") let simple =ConcreteComponent() Client.someClientCode(component: simple)
// ...as well as decorated ones. // // Note how decorators can wrap not only simple components but the other // decorators as well. let decorator1 =ConcreteDecoratorA(simple) let decorator2 =ConcreteDecoratorB(decorator1) print("\nClient: Now I've got a decorated component") Client.someClientCode(component: decorator2) } }
Output.txt: 执行结果
1 2 3 4 5
Client: I've got a simple component Result: ConcreteComponent
Client: Now I've got a decorated component Result: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
print("Client: set up an editors stack") let resizer =Resizer(image, xScale: 0.2, yScale: 0.2)
let blurFilter =BlurFilter(resizer) blurFilter.update(radius: 2)
let colorFilter =ColorFilter(blurFilter) colorFilter.update(contrast: 0.53) colorFilter.update(brightness: 0.12) colorFilter.update(saturation: 4)
clientCode(editor: colorFilter) }
funcclientCode(editor: ImageEditor) { let image = editor.apply() /// Note. You can stop an execution in Xcode to see an image preview. print("Client: all changes have been applied for \(image)") } }
privateextensionDecoratorRealWorld {
funcloadImage() -> UIImage {
let urlString ="https:// refactoring.guru/images/content-public/logos/logo-new-3x.png"
/// Note: /// Do not download images the following way in a production code.
guardlet url =URL(string: urlString) else { fatalError("Please enter a valid URL") }
guardlet data =try?Data(contentsOf: url) else { fatalError("Cannot load an image") }
guardlet image =UIImage(data: data) else { fatalError("Cannot create an image from data") } return image } }
/** * The base Component interface defines operations that can be altered by * decorators. */ interfaceComponent { operation(): string; }
/** * Concrete Components provide default implementations of the operations. There * might be several variations of these classes. */ classConcreteComponentimplementsComponent { publicoperation(): string { return'ConcreteComponent'; } }
/** * The base Decorator class follows the same interface as the other components. * The primary purpose of this class is to define the wrapping interface for all * concrete decorators. The default implementation of the wrapping code might * include a field for storing a wrapped component and the means to initialize * it. */ classDecoratorimplementsComponent { protectedcomponent: Component;
/** * The Decorator delegates all work to the wrapped component. */ publicoperation(): string { returnthis.component.operation(); } }
/** * Concrete Decorators call the wrapped object and alter its result in some way. */ classConcreteDecoratorAextendsDecorator { /** * Decorators may call parent implementation of the operation, instead of * calling the wrapped object directly. This approach simplifies extension * of decorator classes. */ publicoperation(): string { return`ConcreteDecoratorA(${super.operation()})`; } }
/** * Decorators can execute their behavior either before or after the call to a * wrapped object. */ classConcreteDecoratorBextendsDecorator { publicoperation(): string { return`ConcreteDecoratorB(${super.operation()})`; } }
/** * The client code works with all objects using the Component interface. This * way it can stay independent of the concrete classes of components it works * with. */ functionclientCode(component: Component) { // ...
console.log(`RESULT: ${component.operation()}`);
// ... }
/** * This way the client code can support both simple components... */ const simple = newConcreteComponent(); console.log('Client: I\'ve got a simple component:'); clientCode(simple); console.log('');
/** * ...as well as decorated ones. * * Note how decorators can wrap not only simple components but the other * decorators as well. */ const decorator1 = newConcreteDecoratorA(simple); const decorator2 = newConcreteDecoratorB(decorator1); console.log('Client: Now I\'ve got a decorated component:'); clientCode(decorator2);
Output.txt: 执行结果
1 2 3 4 5
Client: I've got a simple component: RESULT: ConcreteComponent
Client: Now I've got a decorated component: RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))