खोज…


परिचय

डिज़ाइन पैटर्न उन समस्याओं का सामान्य समाधान है जो अक्सर सॉफ़्टवेयर विकास में होती हैं। निम्नलिखित संरचना और डिजाइनिंग कोड में मानकीकृत सर्वोत्तम प्रथाओं के टेम्पलेट हैं, साथ ही साथ आम संदर्भों के उदाहरण हैं जिसमें ये डिज़ाइन पैटर्न उपयुक्त होंगे।

निर्माण , संरचना और प्रतिनिधित्व की प्रक्रिया से अधिक स्वतंत्र बनाने के लिए रचनात्मक डिजाइन पैटर्न वस्तुओं की तात्कालिकता को सार करते हैं।

एकाकी वस्तु

सिंगलेट्स अक्सर उपयोग किए जाने वाले डिज़ाइन पैटर्न होते हैं जिसमें एक वर्ग का एक एकल उदाहरण शामिल होता है जिसे पूरे कार्यक्रम में साझा किया जाता है।

निम्नलिखित उदाहरण में, हम एक static संपत्ति बनाते हैं जो Foo कक्षा का एक उदाहरण रखती है। याद रखें कि एक static संपत्ति एक वर्ग के सभी वस्तुओं के बीच साझा की जाती है और इसे उपवर्ग द्वारा अधिलेखित नहीं किया जा सकता है।

public class Foo
{
    static let shared = Foo()
    
    // Used for preventing the class from being instantiated directly
    private init() {}
    
    func doSomething()
    {
        print("Do something")
    }
}

उपयोग:

Foo.shared.doSomething()

private इनिशियलाइज़र को याद रखना सुनिश्चित करें:

यह सुनिश्चित करता है कि आपके एकलव्य वास्तव में अद्वितीय हैं और बाहरी वस्तुओं को एक्सेस कंट्रोल के आधार पर अपनी कक्षा के अपने उदाहरण बनाने से रोकते हैं। चूंकि सभी ऑब्जेक्ट स्विफ्ट में एक डिफ़ॉल्ट सार्वजनिक इनिशियलाइज़र के साथ आते हैं, इसलिए आपको अपने इनिट को ओवरराइड करने और इसे निजी बनाने की आवश्यकता है। KrakenDev

फैक्टरी विधि

क्लास-आधारित प्रोग्रामिंग में, फ़ैक्टरी विधि पैटर्न एक रचनात्मक पैटर्न है जो ऑब्जेक्ट के सटीक वर्ग को निर्दिष्ट किए बिना ऑब्जेक्ट बनाने की समस्या से निपटने के लिए फ़ैक्टरी विधियों का उपयोग करता है। विकिपीडिया संदर्भ

protocol SenderProtocol
{
    func send(package: AnyObject)
}

class Fedex: SenderProtocol
{
    func send(package: AnyObject)
    {
        print("Fedex deliver")
    }
}

class RegularPriorityMail: SenderProtocol
{
    func send(package: AnyObject)
    {
        print("Regular Priority Mail deliver")
    }
}

// This is our Factory
class DeliverFactory
{
    // It will be responsable for returning the proper instance that will handle the task
    static func makeSender(isLate isLate: Bool) -> SenderProtocol
    {
        return isLate ? Fedex() : RegularPriorityMail()
    }
}

// Usage:
let package = ["Item 1", "Item 2"]

// Fedex class will handle the delivery
DeliverFactory.makeSender(isLate:true).send(package)

// Regular Priority Mail class will handle the delivery
DeliverFactory.makeSender(isLate:false).send(package)

ऐसा करने से हम कक्षा के वास्तविक कार्यान्वयन पर निर्भर नहीं होते हैं, जिससे sender() पूरी तरह से पारदर्शी होते हैं जो इसका उपभोग कर रहे हैं।

इस मामले में हम सभी को पता होना चाहिए कि एक प्रेषक डिलीवर करेगा और send() नामक विधि को उजागर करेगा। कई अन्य फायदे हैं: कक्षाओं के युग्मन को कम करना, परीक्षण करना आसान, नए व्यवहारों को जोड़ना आसान है बिना परिवर्तन के जो इसे खा रहा है।

ऑब्जेक्ट-ओरिएंटेड डिज़ाइन के भीतर, इंटरफेस एब्सट्रैक्शन की परतें प्रदान करते हैं जो कोड की वैचारिक व्याख्या की सुविधा प्रदान करते हैं और अवरोधक को निर्भरता पैदा करते हैं। विकिपीडिया संदर्भ

देखने वाला

ऑब्जर्वर पैटर्न वह जगह है जहां एक ऑब्जेक्ट, जिसे विषय कहा जाता है, अपने आश्रितों की एक सूची रखता है, जिसे पर्यवेक्षक कहा जाता है, और उन्हें किसी भी राज्य परिवर्तनों के लिए स्वचालित रूप से सूचित करता है, आमतौर पर उनके तरीकों में से एक को कॉल करके। यह मुख्य रूप से वितरित इवेंट हैंडलिंग सिस्टम को लागू करने के लिए उपयोग किया जाता है। ऑब्जर्वर पैटर्न भी परिचित मॉडल-व्यू-कंट्रोलर (एमवीसी) वास्तुशिल्प पैटर्न का एक महत्वपूर्ण हिस्सा है। विकिपीडिया संदर्भ

मूल रूप से पर्यवेक्षक पैटर्न का उपयोग तब किया जाता है जब आपके पास एक वस्तु होती है जो कुछ व्यवहारों या राज्य परिवर्तनों के पर्यवेक्षकों को सूचित कर सकती है।

अधिसूचना केंद्र के लिए पहले एक वैश्विक संदर्भ (एक वर्ग के बाहर) बनाने देता है:

let notifCentre = NotificationCenter.default

महान अब हम इसे कहीं से भी कॉल कर सकते हैं। हम तो एक पर्यवेक्षक के रूप में एक वर्ग रजिस्टर करना चाहते हैं ...

notifCentre.addObserver(self, selector: #selector(self.myFunc), name: "myNotification", object: nil)

यह "readForMyFunc" के लिए एक पर्यवेक्षक के रूप में कक्षा को जोड़ता है। यह यह भी इंगित करता है कि फ़ंक्शन myFunc को कॉल किया जाना चाहिए जब वह सूचना प्राप्त हो। यह फ़ंक्शन समान कक्षा में लिखा जाना चाहिए:

func myFunc(){
    print("The notification has been received")
}

इस पैटर्न के फायदों में से एक यह है कि आप पर्यवेक्षकों के रूप में कई कक्षाएं जोड़ सकते हैं और इस प्रकार एक अधिसूचना के बाद कई कार्य कर सकते हैं।

अधिसूचना अब केवल पंक्ति के साथ कोड में कहीं से भी भेजी जा सकती है (या यदि आप चाहें तो पोस्ट की जा सकती हैं):

notifCentre.post(name: "myNotification", object: nil)

आप सूचना को एक शब्दकोश के रूप में भी पास कर सकते हैं

let myInfo = "pass this on"
notifCentre.post(name: "myNotification", object: ["moreInfo":myInfo])

लेकिन फिर आपको अपने फ़ंक्शन के लिए एक अधिसूचना जोड़ने की आवश्यकता है:

func myFunc(_ notification: Notification){
    let userInfo = (notification as NSNotification).userInfo as! [String: AnyObject]
    let passedInfo = userInfo["moreInfo"]
    print("The notification \(moreInfo) has been received")
    //prints - The notification pass this on has been received
}

जिम्मेदारी की चेन

ऑब्जेक्ट-ओरिएंटेड डिज़ाइन में, चेन-ऑफ़-जिम्मेदारी पैटर्न एक डिज़ाइन पैटर्न है जिसमें command ऑब्जेक्ट्स का स्रोत और processing ऑब्जेक्ट्स की एक श्रृंखला होती है। प्रत्येक processing ऑब्जेक्ट में लॉजिक होता है जो कमांड ऑब्जेक्ट्स के प्रकारों को परिभाषित करता है जिन्हें वह संभाल सकता है; बाकी श्रृंखला में अगली processing वस्तु के लिए पारित किए जाते हैं। इस श्रृंखला के अंत में नई processing वस्तुओं को जोड़ने के लिए एक तंत्र भी मौजूद है। विकिपीडिया

उन वर्गों की स्थापना करना जिन्होंने जिम्मेदारी की श्रृंखला बनाई।

पहले हम सभी processing ऑब्जेक्ट के लिए एक इंटरफ़ेस बनाते हैं।

protocol PurchasePower {  
var allowable : Float { get }
  var role : String { get }
  var successor : PurchasePower? { get set }
}

extension PurchasePower {
  func process(request : PurchaseRequest){
    if request.amount < self.allowable {
      print(self.role + " will approve $ \(request.amount) for \(request.purpose)")
    } else if successor != nil {
      successor?.process(request: request)
    }
  }
}

फिर हम command ऑब्जेक्ट बनाते हैं।

struct PurchaseRequest {
  var amount : Float
  var purpose : String
}

अंत में, उन वस्तुओं का निर्माण करना, जिन्होंने जिम्मेदारी की श्रृंखला बनाई।

class ManagerPower : PurchasePower {
  var allowable: Float = 20
  var role : String = "Manager"
  var successor: PurchasePower?
}

class DirectorPower : PurchasePower {
  var allowable: Float = 100
  var role = "Director"
  var successor: PurchasePower?
}

class PresidentPower : PurchasePower {
  var allowable: Float = 5000
  var role = "President"
  var successor: PurchasePower?
}

इसे एक साथ शुरू करने और उसका पीछा करने में:

let manager = ManagerPower()
let director = DirectorPower()
let president = PresidentPower()

manager.successor = director
director.successor = president

यहां वस्तुओं का पीछा करने का तंत्र संपत्ति की पहुंच है

इसे चलाने के लिए अनुरोध बनाना:

manager.process(request: PurchaseRequest(amount: 2, purpose: "buying a pen"))  // Manager will approve $ 2.0 for buying a pen
manager.process(request: PurchaseRequest(amount: 90, purpose: "buying a printer")) // Director will approve $ 90.0 for buying a printer

manager.process(request: PurchaseRequest(amount: 2000, purpose: "invest in stock")) // President will approve $ 2000.0 for invest in stock

इटरेटर

कंप्यूटर प्रोग्रामिंग में एक पुनरावृत्ति एक वस्तु है जो एक प्रोग्रामर को कंटेनर को पार करने में सक्षम बनाता है, विशेष रूप से सूचीबद्ध करता है। विकिपीडिया

struct Turtle {
  let name: String
}

struct Turtles {
  let turtles: [Turtle]
}

struct TurtlesIterator: IteratorProtocol {
  private var current = 0
  private let turtles: [Turtle]

  init(turtles: [Turtle]) {
    self.turtles = turtles
  }

  mutating func next() -> Turtle? {
    defer { current += 1 }
    return turtles.count > current ? turtles[current] : nil
  }
}

extension Turtles: Sequence {
  func makeIterator() -> TurtlesIterator {
    return TurtlesIterator(turtles: turtles)
  }
}

और उपयोग उदाहरण होगा

let ninjaTurtles = Turtles(turtles: [Turtle(name: "Leo"),
                                     Turtle(name: "Mickey"),
                                     Turtle(name: "Raph"),
                                     Turtle(name: "Doney")])
print("Splinter and")
for turtle in ninjaTurtles {
  print("The great: \(turtle)")
}

बिल्डर पैटर्न

बिल्डर पैटर्न एक ऑब्जेक्ट क्रिएशन सॉफ्टवेयर डिज़ाइन पैटर्न है । अमूर्त कारखाने पैटर्न और कारखाने विधि पैटर्न के विपरीत जिसका उद्देश्य बहुरूपता को सक्षम करना है, बिल्डर पैटर्न का उद्देश्य दूरबीन निर्माण विरोधी पैटर्न का समाधान खोजना है। टेलिस्कोपिंग कंस्ट्रक्टर एंटी-पैटर्न तब होता है जब ऑब्जेक्ट कंस्ट्रक्टर पैरामीटर संयोजन की वृद्धि से कंस्ट्रक्टरों की एक घातीय सूची होती है। कई बिल्डरों का उपयोग करने के बजाय, बिल्डर पैटर्न एक अन्य ऑब्जेक्ट का उपयोग करता है, एक बिल्डर, जो प्रत्येक इनिशियलाइज़ेशन पैरामीटर को चरण दर चरण प्राप्त करता है और फिर एक ही बार में परिणामी निर्माण वस्तु को लौटाता है।

-Wikipedia

बिल्डर पैटर्न का मुख्य लक्ष्य किसी रचना के लिए एक डिफ़ॉल्ट कॉन्फ़िगरेशन को उसके निर्माण से सेटअप करना है। यह एक मध्यस्थ है जिसके बीच में वस्तु का निर्माण किया जाएगा और इसके निर्माण से संबंधित अन्य सभी वस्तुएं।

उदाहरण:

इसे और अधिक स्पष्ट करने के लिए, आइए एक कार बिल्डर उदाहरण देखें।

विचार करें कि हमारे पास एक कार क्लास है जिसमें ऑब्जेक्ट बनाने के कई विकल्प हैं, जैसे:

  • रंग।
  • सीटों की संख्या।
  • पहियों की संख्या।
  • प्रकार।
  • गियर का प्रकार।
  • मोटर।
  • एयरबैग की उपलब्धता।
import UIKit

enum CarType {
    case
    
    sportage,
    saloon
}

enum GearType {
    case
    
    manual,
    automatic
}

struct Motor {
    var id: String
    var name: String
    var model: String
    var numberOfCylinders: UInt8
}

class Car: CustomStringConvertible {
    var color: UIColor
    var numberOfSeats: UInt8
    var numberOfWheels: UInt8
    var type: CarType
    var gearType: GearType
    var motor: Motor
    var shouldHasAirbags: Bool
    
    var description: String {
        return "color: \(color)\nNumber of seats: \(numberOfSeats)\nNumber of Wheels: \(numberOfWheels)\n Type: \(gearType)\nMotor: \(motor)\nAirbag Availability: \(shouldHasAirbags)"
    }
    
    init(color: UIColor, numberOfSeats: UInt8, numberOfWheels: UInt8, type: CarType, gearType: GearType, motor: Motor, shouldHasAirbags: Bool) {
        
        self.color = color
        self.numberOfSeats = numberOfSeats
        self.numberOfWheels = numberOfWheels
        self.type = type
        self.gearType = gearType
        self.motor = motor
        self.shouldHasAirbags = shouldHasAirbags
        
    }
}

एक कार वस्तु बनाना:

let aCar = Car(color: UIColor.black,
               numberOfSeats: 4,
               numberOfWheels: 4,
               type: .saloon,
               gearType: .automatic,
               motor: Motor(id: "101", name: "Super Motor",
                            model: "c4", numberOfCylinders: 6),
               shouldHasAirbags: true)

print(aCar)

/* Printing
 color: UIExtendedGrayColorSpace 0 1
 Number of seats: 4
 Number of Wheels: 4
 Type: automatic
 Motor: Motor(id: "101", name: "Super Motor", model: "c4", numberOfCylinders: 6)
 Airbag Availability: true
*/

कार ऑब्जेक्ट बनाते समय समस्या उत्पन्न होती है कि कार को कई कॉन्फ़िगरेशन डेटा बनाने की आवश्यकता होती है।

बिल्डर पैटर्न को लागू करने के लिए, शुरुआती मापदंडों में डिफ़ॉल्ट मान होना चाहिए जो कि जरूरत पड़ने पर परिवर्तनशील हो

CarBuilder वर्ग:

class CarBuilder {
    var color: UIColor = UIColor.black
    var numberOfSeats: UInt8 = 5
    var numberOfWheels: UInt8 = 4
    var type: CarType = .saloon
    var gearType: GearType = .automatic
    var motor: Motor = Motor(id: "111", name: "Default Motor",
                             model: "T9", numberOfCylinders: 4)
    var shouldHasAirbags: Bool = false
    
    func buildCar() -> Car {
        return Car(color: color, numberOfSeats: numberOfSeats, numberOfWheels: numberOfWheels, type: type, gearType: gearType, motor: motor, shouldHasAirbags: shouldHasAirbags)
    }
}

CarBuilder वर्ग उन संपत्तियों को परिभाषित करता है जिन्हें परिवर्तित कार ऑब्जेक्ट के मूल्यों को संपादित करने के लिए बदला जा सकता है।

चलो CarBuilder का उपयोग करके नई कारों का निर्माण करते हैं:

var builder = CarBuilder()
// currently, the builder creates cars with default configuration.

let defaultCar = builder.buildCar()
//print(defaultCar.description)
/* prints
 color: UIExtendedGrayColorSpace 0 1
 Number of seats: 5
 Number of Wheels: 4
 Type: automatic
 Motor: Motor(id: "111", name: "Default Motor", model: "T9", numberOfCylinders: 4)
 Airbag Availability: false
*/

builder.shouldHasAirbags = true
// now, the builder creates cars with default configuration,
// but with a small edit on making the airbags available

let safeCar = builder.buildCar()
print(safeCar.description)
/* prints
 color: UIExtendedGrayColorSpace 0 1
 Number of seats: 5
 Number of Wheels: 4
 Type: automatic
 Motor: Motor(id: "111", name: "Default Motor", model: "T9", numberOfCylinders: 4)
 Airbag Availability: true
 */

builder.color = UIColor.purple
// now, the builder creates cars with default configuration
// with some extra features: the airbags are available and the color is purple

let femaleCar = builder.buildCar()
print(femaleCar)
/* prints
 color: UIExtendedSRGBColorSpace 0.5 0 0.5 1
 Number of seats: 5
 Number of Wheels: 4
 Type: automatic
 Motor: Motor(id: "111", name: "Default Motor", model: "T9", numberOfCylinders: 4)
 Airbag Availability: true
*/

बिल्डर पैटर्न को लागू करने का लाभ उन वस्तुओं को बनाने में आसानी है जिनमें डिफ़ॉल्ट मान सेट करके बहुत अधिक कॉन्फ़िगरेशन होना चाहिए, साथ ही, इन डिफ़ॉल्ट मानों को बदलने में आसानी होती है।

इसे और आगे ले जाएं:

एक अच्छे अभ्यास के रूप में, डिफ़ॉल्ट मूल्यों की आवश्यकता वाले सभी गुणों को एक अलग प्रोटोकॉल में होना चाहिए, जिसे कक्षा और उसके बिल्डर द्वारा लागू किया जाना चाहिए।

हमारे उदाहरण के लिए, चलो एक नया प्रोटोकॉल बनाते हैं, जिसे CarBluePrint कहा जाता है:

import UIKit

enum CarType {
    case
    
    sportage,
    saloon
}

enum GearType {
    case
    
    manual,
    automatic
}

struct Motor {
    var id: String
    var name: String
    var model: String
    var numberOfCylinders: UInt8
}

protocol CarBluePrint {
    var color: UIColor { get set }
    var numberOfSeats: UInt8 { get set }
    var numberOfWheels: UInt8 { get set }
    var type: CarType { get set }
    var gearType: GearType { get set }
    var motor: Motor { get set }
    var shouldHasAirbags: Bool { get set }
}

class Car: CustomStringConvertible, CarBluePrint {
    var color: UIColor
    var numberOfSeats: UInt8
    var numberOfWheels: UInt8
    var type: CarType
    var gearType: GearType
    var motor: Motor
    var shouldHasAirbags: Bool
    
    var description: String {
        return "color: \(color)\nNumber of seats: \(numberOfSeats)\nNumber of Wheels: \(numberOfWheels)\n Type: \(gearType)\nMotor: \(motor)\nAirbag Availability: \(shouldHasAirbags)"
    }
    
    init(color: UIColor, numberOfSeats: UInt8, numberOfWheels: UInt8, type: CarType, gearType: GearType, motor: Motor, shouldHasAirbags: Bool) {
        
        self.color = color
        self.numberOfSeats = numberOfSeats
        self.numberOfWheels = numberOfWheels
        self.type = type
        self.gearType = gearType
        self.motor = motor
        self.shouldHasAirbags = shouldHasAirbags
        
    }
}

class CarBuilder: CarBluePrint {
    var color: UIColor = UIColor.black
    var numberOfSeats: UInt8 = 5
    var numberOfWheels: UInt8 = 4
    var type: CarType = .saloon
    var gearType: GearType = .automatic
    var motor: Motor = Motor(id: "111", name: "Default Motor",
                             model: "T9", numberOfCylinders: 4)
    var shouldHasAirbags: Bool = false
    
    func buildCar() -> Car {
        return Car(color: color, numberOfSeats: numberOfSeats, numberOfWheels: numberOfWheels, type: type, gearType: gearType, motor: motor, shouldHasAirbags: shouldHasAirbags)
    }
}

उन संपत्तियों को घोषित करने का लाभ जो एक प्रोटोकॉल में डिफ़ॉल्ट मूल्य की आवश्यकता होती है, किसी भी नए जोड़े गए संपत्ति को लागू करने के लिए मजबूर करना है; जब कोई वर्ग किसी प्रोटोकॉल के अनुरूप होता है, तो उसे अपने सभी गुणों / विधियों की घोषणा करनी होती है।

विचार करें कि एक आवश्यक नई सुविधा है जिसे "बैटरी नाम" नामक कार बनाने के खाके में जोड़ा जाना चाहिए:

protocol CarBluePrint {
    var color: UIColor { get set }
    var numberOfSeats: UInt8 { get set }
    var numberOfWheels: UInt8 { get set }
    var type: CarType { get set }
    var gearType: GearType { get set }
    var motor: Motor { get set }
    var shouldHasAirbags: Bool { get set }
    
    // adding the new property
    var batteryName: String { get set }
}

नई संपत्ति जोड़ने के बाद, ध्यान दें कि दो संकलन-समय त्रुटियां उत्पन्न होंगी, यह सूचित करते हुए कि CarBluePrint प्रोटोकॉल के अनुरूप 'बैटरीनाम' संपत्ति घोषित करने की आवश्यकता है। यह गारंटी देता है कि CarBuilder batteryName प्रॉपर्टी के लिए डिफ़ॉल्ट मान घोषित करेगी और सेट batteryName

CarBluePrint प्रोटोकॉल में batteryName नई प्रॉपर्टी जोड़ने के बाद, Car और CarBuilder दोनों वर्गों का कार्यान्वयन होना चाहिए:

class Car: CustomStringConvertible, CarBluePrint {
    var color: UIColor
    var numberOfSeats: UInt8
    var numberOfWheels: UInt8
    var type: CarType
    var gearType: GearType
    var motor: Motor
    var shouldHasAirbags: Bool
    var batteryName: String
    
    var description: String {
        return "color: \(color)\nNumber of seats: \(numberOfSeats)\nNumber of Wheels: \(numberOfWheels)\nType: \(gearType)\nMotor: \(motor)\nAirbag Availability: \(shouldHasAirbags)\nBattery Name: \(batteryName)"
    }
    
    init(color: UIColor, numberOfSeats: UInt8, numberOfWheels: UInt8, type: CarType, gearType: GearType, motor: Motor, shouldHasAirbags: Bool, batteryName: String) {
        
        self.color = color
        self.numberOfSeats = numberOfSeats
        self.numberOfWheels = numberOfWheels
        self.type = type
        self.gearType = gearType
        self.motor = motor
        self.shouldHasAirbags = shouldHasAirbags
        self.batteryName = batteryName
    }
}

class CarBuilder: CarBluePrint {
    var color: UIColor = UIColor.red
    var numberOfSeats: UInt8 = 5
    var numberOfWheels: UInt8 = 4
    var type: CarType = .saloon
    var gearType: GearType = .automatic
    var motor: Motor = Motor(id: "111", name: "Default Motor",
                             model: "T9", numberOfCylinders: 4)
    var shouldHasAirbags: Bool = false
    var batteryName: String = "Default Battery Name"
    
    func buildCar() -> Car {
        return Car(color: color, numberOfSeats: numberOfSeats, numberOfWheels: numberOfWheels, type: type, gearType: gearType, motor: motor, shouldHasAirbags: shouldHasAirbags, batteryName: batteryName)
    }
}

फिर से, CarBuilder का उपयोग करके नई कारों का निर्माण करें:

var builder = CarBuilder()

let defaultCar = builder.buildCar()
print(defaultCar)
/* prints
 color: UIExtendedSRGBColorSpace 1 0 0 1
 Number of seats: 5
 Number of Wheels: 4
 Type: automatic
 Motor: Motor(id: "111", name: "Default Motor", model: "T9", numberOfCylinders: 4)
 Airbag Availability: false
 Battery Name: Default Battery Name
*/

builder.batteryName = "New Battery Name"

let editedBatteryCar = builder.buildCar()
print(editedBatteryCar)
/*
 color: UIExtendedSRGBColorSpace 1 0 0 1
 Number of seats: 5
 Number of Wheels: 4
 Type: automatic
 Motor: Motor(id: "111", name: "Default Motor", model: "T9", numberOfCylinders: 4)
 Airbag Availability: false
 Battery Name: New Battery Name
 */


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow