সুইফট ল্যাঙ্গুয়েজে অ্যাবস্ট্রাক্ট ক্লাস


140

সুইফট ল্যাঙ্গুয়েজে কোনও বিমূর্ত শ্রেণি তৈরি করার কোনও উপায় আছে, বা এটি কেবলমাত্র উদ্দেশ্য-সি এর মতো একটি সীমাবদ্ধতা? জাভা যা বিমূর্ত শ্রেণীর হিসাবে সংজ্ঞায়িত করেছে তার সাথে তুলনামূলক আমি একটি বিমূর্ত শ্রেণি তৈরি করতে চাই।


বিমূর্ত বা এটিতে কেবল কিছু পদ্ধতিতে পূর্ণ শ্রেণীর প্রয়োজন কি? একক পদ্ধতি এবং বৈশিষ্ট্যগুলির জন্য এখানে উত্তরটি দেখুন। stackoverflow.com/a/39038828/2435872 । জাভাতে আপনি বিমূর্ত ক্লাসগুলিতে বেড়াতে পারেন, যেগুলির কোনও বিমূর্ত পদ্ধতি নেই। এই বিশেষ বৈশিষ্ট্যটি সুইফ্ট সরবরাহ করেনি।
jboi

উত্তর:


174

সুইফটে কোনও অ্যাবস্ট্রাক্ট ক্লাস নেই (ঠিক ওজেক্টিভ-সি এর মতো)। আপনার সেরা বাজিটি প্রোটোকল ব্যবহার করতে চলেছে যা জাভা ইন্টারফেসের মতো।

সুইফট ২.০ দিয়ে আপনি প্রোটোকল এক্সটেনশানগুলি ব্যবহার করে পদ্ধতি প্রয়োগ এবং গণনা করা সম্পত্তি প্রয়োগগুলি যুক্ত করতে পারেন। আপনার কেবলমাত্র বিধিনিষেধগুলি হ'ল আপনি সদস্য ভেরিয়েবল বা ধ্রুবক সরবরাহ করতে পারবেন না এবং কোনও গতিশীল প্রেরণ নেই

এই কৌশলটির উদাহরণ হ'ল:

protocol Employee {
    var annualSalary: Int {get}
}

extension Employee {
    var biweeklySalary: Int {
        return self.annualSalary / 26
    }

    func logSalary() {
        print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly")
    }
}

struct SoftwareEngineer: Employee {
    var annualSalary: Int

    func logSalary() {
        print("overridden")
    }
}

let sarah = SoftwareEngineer(annualSalary: 100000)
sarah.logSalary() // prints: overridden
(sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly

লক্ষ্য করুন যে এটি স্ট্রাক্টগুলির জন্য বৈশিষ্ট্যগুলির মতো "অ্যাবস্ট্রাক্ট ক্লাস" সরবরাহ করছে তবে ক্লাসগুলি একই প্রোটোকলটি প্রয়োগ করতে পারে।

এছাড়াও লক্ষ করুন যে কর্মচারী প্রোটোকল প্রয়োগ করে এমন প্রতিটি শ্রেণি বা কাঠামোকে আবার বার্ষিক স্যালারি সম্পত্তি ঘোষণা করতে হবে।

সবচেয়ে গুরুত্বপূর্ণ, লক্ষ্য করুন যে কোনও গতিশীল প্রেরণ নেই । যখন logSalaryসংরক্ষণ করা হয় সেই উদাহরণে যখন ডাকা হয় তখন SoftwareEngineerএটি পদ্ধতির ওভাররাইড সংস্করণকে কল করে। logSalaryএটি কাস্ট করার পরে উদাহরণটিতে যখন ডাকা হয় Employee, তখন এটি মূল বাস্তবায়নকে ডেকে তোলে (উদাহরণটি আসলে একটি হলেও এটি ওভাররাইড সংস্করণে গতিশীলভাবে প্রেরণ করে না Software Engineer

আরও তথ্যের জন্য, সেই বৈশিষ্ট্যটি সম্পর্কে দুর্দান্ত ডাব্লুডাব্লুডিসি ভিডিও দেখুন: সুইফটে মান ধরণের সাথে আরও ভাল অ্যাপ্লিকেশন তৈরি করা


3
protocol Animal { var property : Int { get set } }। আপনি যদি সম্পত্তিটি কোনও সেটার রাখতে না চান তবে আপনি সেটটিও ছেড়ে দিতে পারেন
55


2
@ মারিওজান্নোন সেই ভিডিওটি কেবল আমার মনকে উড়িয়ে দিয়েছে এবং আমাকে সুইফ্টের প্রেমে পড়েছে।
স্কট এইচ

3
আপনি যদি কেবলমাত্র func logSalary()কর্মচারী প্রোটোকল ঘোষণায় যুক্ত করেন তবে উদাহরণটি overriddenউভয় কলের জন্য মুদ্রণ করে logSalary()। এটি সুইফট ৩.১-এ রয়েছে। এইভাবে আপনি পলিমারফিজমের সুবিধা পাবেন। উভয় ক্ষেত্রেই সঠিক পদ্ধতিটি বলা হয়।
মাইক টাভেরনে

1
গতিশীল প্রেরণের নিয়মটি হ'ল ... যদি পদ্ধতিটি কেবল এক্সটেনশনে সংজ্ঞায়িত করা হয় তবে এটি স্থিতিশীলভাবে প্রেরণ করা হয়। আপনি যে প্রোটোকলটি প্রসারিত করছেন তাতে এটি যদি সংজ্ঞায়িত হয় তবে তা গতিশীলভাবে প্রেরণ করা হয়। অবজেক্টিভ-সি রানটাইমের প্রয়োজন নেই। এটি খাঁটি সুইফ্ট আচরণ।
মার্ক এ। ডোনোহো

47

মনে রাখবেন যে এই উত্তরটি সুইফট ২.০ এবং তারপরে লক্ষ্যবস্তু রয়েছে

প্রোটোকল এবং প্রোটোকল এক্সটেনশনের সাহায্যে আপনি একই আচরণ অর্জন করতে পারেন।

প্রথমে, আপনি এমন একটি প্রোটোকল লিখুন যা সমস্ত পদ্ধতিতে এটির সাথে মানানসই পদ্ধতিতে প্রয়োগ করতে হবে যা ইন্টারফেস হিসাবে কাজ করে।

protocol Drivable {
    var speed: Float { get set }
}

তারপরে আপনি তার সাথে সম্মত সমস্ত ধরণের ডিফল্ট আচরণ যুক্ত করতে পারেন

extension Drivable {
    func accelerate(by: Float) {
        speed += by
    }
}

আপনি এখন প্রয়োগ করে নতুন ধরণের তৈরি করতে পারেন Drivable

struct Car: Drivable {
    var speed: Float = 0.0
    init() {}
}

let c = Car()
c.accelerate(10)

সুতরাং মূলত আপনি পাবেন:

  1. কম্পাইল সময় চেক করে গ্যারান্টি যে সব Drivableগুলি বাস্তবায়নspeed
  2. Drivable( accelerate) মেনে চলতে পারে এমন সমস্ত ধরণের জন্য আপনি ডিফল্ট-আচরণ প্রয়োগ করতে পারেন
  3. Drivable এটি কেবল একটি প্রোটোকল হওয়ায় তাত্ক্ষণিক না হওয়ার গ্যারান্টিযুক্ত

এই মডেলটি আরও অনেকগুলি বৈশিষ্ট্যের মতো আচরণ করে, এর অর্থ আপনি একাধিক প্রোটোকলের সাথে খাপ খাইয়ে নিতে পারেন এবং এর যে কোনও একটির ডিফল্ট বাস্তবায়ন করতে পারেন, তবে একটি বিমূর্ত সুপারক্লাসের সাহায্যে আপনি একটি সাধারণ শ্রেণিবিন্যাসের মধ্যে সীমাবদ্ধ।


তবুও, কিছু প্রোটোকল বাড়ানোর সম্ভাবনা সবসময় থাকে না, উদাহরণস্বরূপ UICollectionViewDatasource,। আমি সমস্ত বয়লারপ্লেট অপসারণ করতে এবং এটি পৃথক প্রোটোকল / এক্সটেনশনে আবদ্ধ করতে এবং তারপরে একাধিক শ্রেণীর দ্বারা পুনরায় ব্যবহার করতে চাই। আসলে, টেম্পলেট
নিদর্শনটি

1
আপনি ˚Car˚ এ celeএক্সিটারেট˚ ওভাররাইট করতে পারবেন না ˚ যদি আপনি এটি করেন তবে Drive এক্সটেনশন ড্রাইভযোগ্য in এ বাস্তবায়নের জন্য কোনও সংকলক সতর্কতা ছাড়াই ডাকা হবে। খুব জাভা বিমূর্ত শ্রেণীর মতো নয়
গার্ড কাস্তান

@ গ্রেডকাস্টান সত্য, প্রোটোকল এক্সটেনশনগুলি গতিশীল প্রেরণকে সমর্থন করে না।
ইলুটোভ

15

আমি মনে করি এটি জাভা abstractবা সি # এর নিকটতম abstract:

class AbstractClass {

    private init() {

    }
}

নোট করুন যে, privateসংশোধনকারীদের কাজ করার জন্য আপনাকে অবশ্যই এই শ্রেণিটি একটি পৃথক সুইফ্ট ফাইলে সংজ্ঞায়িত করতে হবে।

সম্পাদনা: তবুও, এই কোডটি একটি বিমূর্ত পদ্ধতি ঘোষণা করার অনুমতি দেয় না এবং এভাবে এর প্রয়োগকে বাধ্য করে।


4
তবুও, এটি একটি সাবক্লাসকে প্যারেন্ট ক্লাসে সেই ফাংশনটির বেস বাস্তবায়ন করার সময় কোনও ক্রিয়াকে ওভাররাইড করতে বাধ্য করে না ।
ম্যাথু কুইরোস

সি # তে, আপনি যদি একটি বিমূর্ত বেস শ্রেণিতে কোনও ফাংশন বাস্তবায়ন করেন, আপনি এটির সাবক্লাসে এটি প্রয়োগ করতে বাধ্য হবেন না। তবুও, এই কোডটি আপনাকে ওভাররাইডকে বাধ্য করার জন্য কোনও বিমূর্ত পদ্ধতি ঘোষণা করার অনুমতি দেয় না।
তিজয়

বলুন যে কংক্রিটক্লাস সাবক্লাস যা অ্যাবস্ট্রাকশ্লাস। কীভাবে আপনি কংক্রিটক্লাস ইনস্ট্যান্ট করবেন?
জাভিয়ের ক্যাডিজ

2
কংক্রিটক্লাসের একটি পাবলিক কনস্ট্রাক্টর থাকা উচিত। আপনার সম্ভবত অ্যাবস্ট্রাক ক্লাসে সুরক্ষিত কনস্ট্রাক্টর দরকার, যদি না তারা একই ফাইলে থাকে। আমার যা মনে আছে তার অনুসারে, সুইফটে সুরক্ষিত অ্যাক্সেস পরিবর্তনকারী উপস্থিত নেই not সুতরাং সমাধানটি একই ফাইলটিতে কংক্রিটক্লাস ঘোষণা করা।
তেজয়

13

সহজ উপায় হ'ল fatalError("Not Implemented")প্রোটোকল এক্সটেনশনে অ্যাবস্ট্রাক্ট পদ্ধতিতে (পরিবর্তনশীল নয়) কোনও কলটি ব্যবহার করা।

protocol MyInterface {
    func myMethod() -> String
}


extension MyInterface {

    func myMethod() -> String {
        fatalError("Not Implemented")
    }

}

class MyConcreteClass: MyInterface {

    func myMethod() -> String {
        return "The output"
    }

}

MyConcreteClass().myMethod()

এটি একটি দুর্দান্ত উত্তর। আমি বলিনি যে আপনি যদি ডেকে কাজ (MyConcreteClass() as MyInterface).myMethod()করেন তবে এটি কাজ করে! myMethodপ্রোটোকল ঘোষণার মধ্যে কীটি অন্তর্ভুক্ত রয়েছে ; অন্যথায় কল ক্রাশ হয়ে গেছে।
মাইক

11

আমি বেশ কয়েক সপ্তাহ লড়াই করার পরে অবশেষে বুঝতে পারলাম কীভাবে জাভা / পিএইচপি অ্যাবস্ট্রাক্ট ক্লাসটি সুইফটে অনুবাদ করতে হবে:

public class AbstractClass: NSObject {

    internal override init(){}

    public func getFoodToEat()->String
    {
        if(self._iAmHungry())
        {
            return self._myFavoriteFood();
        }else{
            return "";
        }
    }

    private func _myFavoriteFood()->String
    {
        return "Sandwich";
    }

    internal func _iAmHungry()->Bool
    {
        fatalError(__FUNCTION__ + "Must be overridden");
        return false;
    }
}

public class ConcreteClass: AbstractClass, IConcreteClass {

    private var _hungry: Bool = false;

    public override init() {
        super.init();
    }

    public func starve()->Void
    {
        self._hungry = true;
    }

    public override func _iAmHungry()->Bool
    {
        return self._hungry;
    }
}

public protocol IConcreteClass
{
    func _iAmHungry()->Bool;
}

class ConcreteClassTest: XCTestCase {

    func testExample() {

        var concreteClass: ConcreteClass = ConcreteClass();

        XCTAssertEqual("", concreteClass.getFoodToEat());

        concreteClass.starve();

        XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
    }
}

তবে আমি মনে করি অ্যাপল বিমূর্ত শ্রেণি প্রয়োগ করেনি কারণ এটি সাধারণত ডেলিগেট + প্রোটোকল প্যাটার্ন ব্যবহার করে। উদাহরণস্বরূপ, উপরের একই প্যাটার্নটি আরও ভালভাবে করা হবে:

import UIKit

    public class GoldenSpoonChild
    {
        private var delegate: IStomach!;

        internal init(){}

        internal func setup(delegate: IStomach)
        {
            self.delegate = delegate;
        }

        public func getFoodToEat()->String
        {
            if(self.delegate.iAmHungry())
            {
                return self._myFavoriteFood();
            }else{
                return "";
            }
        }

        private func _myFavoriteFood()->String
        {
            return "Sandwich";
        }
    }

    public class Mother: GoldenSpoonChild, IStomach
    {

        private var _hungry: Bool = false;

        public override init()
        {
            super.init();
            super.setup(self);
        }

        public func makeFamilyHungry()->Void
        {
            self._hungry = true;
        }

        public func iAmHungry()->Bool
        {
            return self._hungry;
        }
    }

    protocol IStomach
    {
        func iAmHungry()->Bool;
    }

    class DelegateTest: XCTestCase {

        func testGetFood() {

            var concreteClass: Mother = Mother();

            XCTAssertEqual("", concreteClass.getFoodToEat());

            concreteClass.makeFamilyHungry();

            XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
        }
    }

আমার এই ধরণের প্যাটার্নের প্রয়োজন ছিল কারণ আমি ইউআইটিএবলভিউ কনট্রোলার যেমন ভিউইল অ্যাপয়ার ইত্যাদিতে কিছু পদ্ধতি সাধারণ করতে চেয়েছিলাম এটি কি সহায়ক ছিল?


1
+1 আপনি প্রথমে উল্লিখিত একই পদ্ধতির কাজ করার পরিকল্পনা করছিলেন; প্রতিনিধি প্যাটার্ন আকর্ষণীয় পয়েন্টার।
অঙ্গদ

এছাড়াও, আপনার উভয় উদাহরণ একই ব্যবহারের ক্ষেত্রে থাকলে এটি সহায়তা করবে। গোল্ডেনস্পুনচিল্ড একটি সামান্য বিভ্রান্তিকর নাম, বিশেষত মায়ের মনে হয় যে এটি প্রসারিত করছে।
অঙ্গদ

@ বঙ্গ প্রতিনিধি প্যাটার্ন একই ব্যবহার ক্ষেত্রে, তবে এটি অনুবাদ নয়; এটি একটি ভিন্ন ধাঁচ তাই এটি অবশ্যই আলাদা দৃষ্টিকোণ গ্রহণ করা উচিত।
জোশ উডকক

8

প্রোটোকল ব্যবহার করে বিমূর্ত শ্রেণির অনুকরণের জন্য একটি উপায় রয়েছে। এটি একটি উদাহরণ:

protocol MyProtocol {
   func doIt()
}

class BaseClass {
    weak var myDelegate: MyProtocol?

    init() {
        ...
    }

    func myFunc() {
        ...
        self.myDelegate?.doIt()
        ...
    }
}

class ChildClass: BaseClass, MyProtocol {
    override init(){
        super.init()
        self.myDelegate = self
    }

    func doIt() {
        // Custom implementation
    }
}

1

আপনি কীভাবে বিমূর্ত শ্রেণি প্রয়োগ করতে পারবেন তার আরও একটি উপায় হ'ল ইনিশিয়ালাইজারটি ব্লক করা। আমি এটি এইভাবে সম্পন্ন করেছি:

class Element:CALayer { // IT'S ABSTRACT CLASS

    override init(){ 
        super.init()
        if self.dynamicType === Element.self {
        fatalError("Element is abstract class, do not try to create instance of this class")
        }
    }
}

4
এটি কোনও গ্যারান্টি এবং / অথবা চেক সরবরাহ করে না। রানটাইমের সময় ফুঁক দেওয়া নিয়ম প্রয়োগের একটি খারাপ উপায়। দীক্ষাটি ব্যক্তিগত হিসাবে রাখা ভাল।
Морт

বিমূর্ত শ্রেণীর বিমূর্ত পদ্ধতিগুলির জন্য সমর্থনও থাকা উচিত।
ক্রিশ্তিক

@ ক্রিশটিক আমি মূল ধারণাটি দেখিয়েছি, এটি সম্পূর্ণ সমাধান নয়। এইভাবে আপনি 80% উত্তর অপছন্দ করতে পারেন কারণ সেগুলি আপনার পরিস্থিতির জন্য যথেষ্ট বিশদ নয়
আলেক্সি ইয়ারমোলোভিচ

1
@ আলেক্সিইয়ারমোলোভিচ কে বলেছে যে আমি ৮০% উত্তর অপছন্দ করছি না? :) একসাথে উপস্থাপিত হয়ে, আমি আপনাকে পরামর্শ দিচ্ছিলাম যে আপনার উদাহরণটি আরও উন্নত করা যায়, এটি অন্যান্য পাঠকদের সহায়তা করবে এবং উন্নতি করে আপনাকে সহায়তা করবে।
ক্রিশ্চিক

0

আমি একটি Weatherবিমূর্ত ক্লাস করার চেষ্টা করছিলাম , তবে প্রোটোকল ব্যবহার করা আদর্শ ছিল না কারণ আমাকে একই initপদ্ধতি বারবার লিখতে হয়েছিল । প্রোটোকলটি প্রসারিত করা এবং একটি initপদ্ধতি লেখার ক্ষেত্রে এটির সমস্যা ছিল, বিশেষত যেহেতু আমি NSObjectমেনে চলছি NSCoding

সুতরাং আমি NSCodingকনফারেন্সের জন্য এটি নিয়ে এসেছি :

required init?(coder aDecoder: NSCoder) {
    guard type(of: self) != Weather.self else {
        fatalError("<Weather> This is an abstract class. Use a subclass of `Weather`.")
    }
    // Initialize...
}        

হিসাবে হিসাবে init:

fileprivate init(param: Any...) {
    // Initialize
}

0

বিমূর্ত বৈশিষ্ট্য এবং বেস শ্রেণীর পদ্ধতির সমস্ত উল্লেখ প্রোটোকল এক্সটেনশন বাস্তবায়নে সরান, যেখানে বেস শ্রেণিতে স্ব-বাধা। আপনি বেস ক্লাসের সমস্ত পদ্ধতি এবং বৈশিষ্ট্যে অ্যাক্সেস পাবেন gain সংযোজনযোগ্য ক্লাসগুলির জন্য প্রোটোকলে বিমূর্ত পদ্ধতি এবং বৈশিষ্ট্যগুলির প্রয়োগ বাস্তবায়ন সংকলক

protocol Commom:class{
  var tableView:UITableView {get};
  func update();
}

class Base{
   var total:Int = 0;
}

extension Common where Self:Base{
   func update(){
     total += 1;
     tableView.reloadData();
   }
} 

class Derived:Base,Common{
  var tableView:UITableView{
    return owner.tableView;
  }
}

0

কোনও গতিশীল প্রেরণের সীমাবদ্ধতা না থাকলে আপনি এমন কিছু করতে পারেন:

import Foundation

protocol foo {

    static var instance: foo? { get }
    func prt()

}

extension foo {

    func prt() {
        if Thread.callStackSymbols.count > 30 {
            print("super")
        } else {
            Self.instance?.prt()
        }
    }

}

class foo1 : foo {

    static var instance : foo? = nil

    init() {
        foo1.instance = self
    }

    func prt() {
        print("foo1")
    }

}

class foo2 : foo {

    static var instance : foo? = nil

    init() {
        foo2.instance = self
    }

    func prt() {
        print("foo2")
    }

}

class foo3 : foo {

    static var instance : foo? = nil

    init() {
        foo3.instance = self
    }

}

var f1 : foo = foo1()
f1.prt()
var f2 : foo = foo2()
f2.prt()
var f3 : foo = foo3()
f3.prt()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.